From b6401b776f2cd2bd253d88f304ae871ce0ce34db Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Fri, 11 Dec 2020 16:50:49 +0800 Subject: [PATCH 01/27] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E4=BF=AE=E5=A4=8D=E6=89=A7=E8=A1=8C=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/components/api/definition/ApiDefinition.vue | 5 ++++- .../components/api/definition/components/ApiConfig.vue | 6 +++++- .../api/definition/components/runtest/RunTestHTTPPage.vue | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/frontend/src/business/components/api/definition/ApiDefinition.vue b/frontend/src/business/components/api/definition/ApiDefinition.vue index 1c07087dfd..a3d9095a71 100644 --- a/frontend/src/business/components/api/definition/ApiDefinition.vue +++ b/frontend/src/business/components/api/definition/ApiDefinition.vue @@ -154,7 +154,10 @@ } }, handleTabAdd(e) { - let api = {status: "Underway", method: "GET", userId: getCurrentUser().id, url: "", protocol: this.currentProtocol}; + let api = { + status: "Underway", method: "GET", userId: getCurrentUser().id, + url: "", protocol: this.currentProtocol, environmentId: "" + }; this.handleTabsEdit(this.$t('api_test.definition.request.title'), e, api); }, handleTabClose() { diff --git a/frontend/src/business/components/api/definition/components/ApiConfig.vue b/frontend/src/business/components/api/definition/components/ApiConfig.vue index e9e1ae765b..1df8d46921 100644 --- a/frontend/src/business/components/api/definition/components/ApiConfig.vue +++ b/frontend/src/business/components/api/definition/components/ApiConfig.vue @@ -64,7 +64,11 @@ break; } if (this.currentApi.response != null && this.currentApi.response != 'null' && this.currentApi.response != undefined) { - this.response = new ResponseFactory(JSON.parse(this.currentApi.response)); + if (Object.prototype.toString.call(this.currentApi.response).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') { + this.response = this.currentApi.response; + } else { + this.response = new ResponseFactory(JSON.parse(this.currentApi.response)); + } } else { this.response = {headers: [], body: new Body(), statusCode: [], type: "HTTP"}; } diff --git a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue index c65a36cc60..1b2ba625bb 100644 --- a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue +++ b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue @@ -236,7 +236,7 @@ let hasEnvironment = false; for (let i in this.environments) { if (this.environments[i].id === this.api.environmentId) { - this.api.environment = this.environments[i]; + this.api.environmentId = this.environments[i]; hasEnvironment = true; break; } @@ -261,7 +261,8 @@ environmentChange(value) { for (let i in this.environments) { if (this.environments[i].id === value) { - this.api.request.useEnvironment = this.environments[i].id; + this.api.environmentId = value; + this.api.request.useEnvironment = value; break; } } From 721206ac7fc75f3c4719ad58514d84431ed61f41 Mon Sep 17 00:00:00 2001 From: shiziyuan9527 Date: Fri, 11 Dec 2020 17:33:48 +0800 Subject: [PATCH 02/27] =?UTF-8?q?fix:=20=E5=88=A0=E9=99=A4=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=90=8E=E5=88=87=E6=8D=A2=E5=BD=93=E5=89=8D=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/business/components/settings/project/MsProject.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/business/components/settings/project/MsProject.vue b/frontend/src/business/components/settings/project/MsProject.vue index c43911e37b..8e22b5eb9f 100644 --- a/frontend/src/business/components/settings/project/MsProject.vue +++ b/frontend/src/business/components/settings/project/MsProject.vue @@ -88,7 +88,7 @@ import MsTablePagination from "../../common/pagination/TablePagination"; import MsTableHeader from "../../common/components/MsTableHeader"; import MsTableOperator from "../../common/components/MsTableOperator"; import MsDialogFooter from "../../common/components/MsDialogFooter"; -import {_sort, getCurrentUser, listenGoBack, removeGoBackListener} from "@/common/js/utils"; +import {_sort, getCurrentProjectID, getCurrentUser, listenGoBack, removeGoBackListener} from "@/common/js/utils"; import MsContainer from "../../common/components/MsContainer"; import MsMainContainer from "../../common/components/MsMainContainer"; import MsDeleteConfirm from "../../common/components/MsDeleteConfirm"; @@ -96,6 +96,7 @@ import MsTableOperatorButton from "../../common/components/MsTableOperatorButton import ApiEnvironmentConfig from "../../api/test/components/ApiEnvironmentConfig"; import TemplateComponent from "../../track/plan/view/comonents/report/TemplateComponent/TemplateComponent"; import {ApiEvent, LIST_CHANGE, PerformanceEvent, TrackEvent} from "@/business/components/common/head/ListEvent"; +import {PROJECT_ID} from "@/common/js/constants"; export default { name: "MsProject", @@ -216,6 +217,10 @@ export default { type: 'warning' }).then(() => { this.$get('/project/delete/' + project.id, () => { + if (project.id === getCurrentProjectID()) { + localStorage.removeItem(PROJECT_ID); + this.$post("/user/update/current", {id: getCurrentUser().id, lastProjectId: ''}); + } Message.success(this.$t('commons.delete_success')); this.list(); // 发送广播,刷新 head 上的最新列表 From 7d746055330c158b766b032c2058b7fc759f0e76 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Fri, 11 Dec 2020 18:01:38 +0800 Subject: [PATCH 03/27] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E7=BC=BA=E9=99=B7=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/definition/components/ApiCaseList.vue | 24 ++++++++++++------- .../components/case/ApiCaseHeader.vue | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/frontend/src/business/components/api/definition/components/ApiCaseList.vue b/frontend/src/business/components/api/definition/components/ApiCaseList.vue index f1b056d9ef..3fbb20dad8 100644 --- a/frontend/src/business/components/api/definition/components/ApiCaseList.vue +++ b/frontend/src/business/components/api/definition/components/ApiCaseList.vue @@ -29,7 +29,7 @@ - + @@ -57,11 +57,11 @@ + style="background-color: #409EFF;color: white" size="mini" :disabled="item.type=='create'" circle/> + size="mini" :disabled="item.type=='create'" circle/> + size="mini" :disabled="item.type=='create'" circle/> @@ -222,7 +222,6 @@ this.$warning(this.$t('api_test.environment.select_environment')); return; } - this.loading = true; if (this.apiCaseList.length > 0) { this.apiCaseList.forEach(item => { if (item.type != "create") { @@ -231,9 +230,13 @@ this.runData.push(item.request); } }) - this.loading = true; - /*触发执行操作*/ - this.reportId = getUUID().substring(0, 8); + if (this.runData.length > 0) { + this.loading = true; + /*触发执行操作*/ + this.reportId = getUUID().substring(0, 8); + } else { + this.$warning("没有可执行的用例!"); + } } else { this.$warning("没有可执行的用例!"); } @@ -343,6 +346,11 @@ return true; } }, + changePriority(row) { + if (row.type != 'create') { + this.saveTestCase(row); + } + }, saveTestCase(row) { if (this.validate(row)) { return; 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 78b9ddfcd6..8fe0bef3d9 100644 --- a/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue +++ b/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue @@ -48,7 +48,7 @@
+ v-model="condition.name" @blur="getApiTest" @keyup.enter.native="getApiTest"/>
From 2d381a14fb5b321c0842cda9cf580f8d21e54e5c Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Fri, 11 Dec 2020 18:10:18 +0800 Subject: [PATCH 04/27] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A3=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=8C=96):=20=E7=BB=9F=E4=B8=80=E6=89=A7=E8=A1=8C=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/service/ApiAutomationService.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 21b416fb4e..498e178e37 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -242,12 +242,16 @@ public class ApiAutomationService { JSONObject element = JSON.parseObject(item.getScenarioDefinition()); MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class); // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 - LinkedList elements = mapper.readValue(element.getString("hashTree"), - new TypeReference>() {}); - LinkedList variables = mapper.readValue(element.getString("variables"), - new TypeReference>() {}); - scenario.setHashTree(elements); - scenario.setVariables(variables); + if (StringUtils.isNotEmpty(element.getString("hashTree"))) { + LinkedList elements = mapper.readValue(element.getString("hashTree"), + new TypeReference>() {}); + scenario.setHashTree(elements); + } + if (StringUtils.isNotEmpty(element.getString("variables"))) { + LinkedList variables = mapper.readValue(element.getString("variables"), + new TypeReference>() {}); + scenario.setVariables(variables); + } LinkedList scenarios = new LinkedList<>(); scenarios.add(scenario); group.setHashTree(scenarios); From d9d91ebd7110578fd49f2021fdda002edfbe0dc6 Mon Sep 17 00:00:00 2001 From: BugKing Date: Fri, 11 Dec 2020 18:13:51 +0800 Subject: [PATCH 05/27] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b096fc70dc..b8bcefc10c 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# MeterSphere 开源持续测试平台 +# MeterSphere 一站式开源持续测试平台 [![Codacy Badge](https://api.codacy.com/project/badge/Grade/176186d132df448b955f8bdd5e6ef9c0)](https://app.codacy.com/gh/metersphere/metersphere?utm_source=github.com&utm_medium=referral&utm_content=metersphere/metersphere&utm_campaign=Badge_Grade_Dashboard) [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/metersphere/metersphere)](https://github.com/metersphere/metersphere/releases/latest) @@ -11,7 +11,7 @@ | ------------------------------------------------------------------------------------------------------------ | | 我们正在寻找开发者,欢迎加入我们共同打造更好用、更强大的 MeterSphere。联系我们: [metersphere@fit2cloud.com](mailto:metersphere@fit2cloud.com) | -MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟踪、接口测试、性能测试、团队协作等功能,兼容JMeter 等开源标准,有效助力开发和测试团队充分利用云弹性进行高度可扩展的自动化测试,加速高质量软件的交付。 +MeterSphere 是一站式开源持续测试平台,涵盖测试跟踪、接口测试、性能测试、团队协作等功能,兼容JMeter 等开源标准,有效助力开发和测试团队充分利用云弹性进行高度可扩展的自动化测试,加速高质量软件的交付。 - 测试跟踪: 远超 TestLink 的使用体验; - 接口测试: 类似 Postman 的体验; From 9ff168a539eded9998ff7907368ba68bd35c6cd0 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Fri, 11 Dec 2020 18:24:25 +0800 Subject: [PATCH 06/27] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A3=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=8C=96):=20=E7=BB=9F=E4=B8=80=E6=8A=A5=E5=91=8A=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/java/io/metersphere/xpack | 2 +- .../components/api/automation/scenario/ApiScenarioList.vue | 6 ++++-- .../components/api/automation/scenario/EditApiScenario.vue | 5 ++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index bb494fc68a..905ca8af61 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit bb494fc68a2367359c9048fa7250c7618de4afb6 +Subproject commit 905ca8af61ce966d26109e9c5c8c0aee3ca1324e diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index 1d3a1b4a7a..7214df3c1c 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -65,7 +65,7 @@ :total="total"/>
- + @@ -265,5 +265,7 @@ diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index 0d3c8a142a..9d629a8cba 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -261,7 +261,7 @@ - + @@ -861,4 +861,7 @@ /deep/ .el-step__icon.is-text { border: 1px solid; } + /deep/.el-drawer__header{ + margin-bottom: 0px; + } From 0bd4675886c9875c36a9292d2e0d6ef6ac8a0b3d Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Fri, 11 Dec 2020 19:14:54 +0800 Subject: [PATCH 07/27] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89?= =?UTF-8?q?):=20=E6=A1=88=E4=BE=8B=E6=89=A7=E8=A1=8C=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E6=9F=A5=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/definition/ApiDefinition.vue | 16 +++++++----- .../api/definition/components/ApiCaseList.vue | 9 ++++++- .../api/definition/components/ApiList.vue | 5 +++- .../components/debug/DebugDubboPage.vue | 23 ++++++++++++++++- .../components/debug/DebugHttpPage.vue | 25 +++++++++++++++++-- .../components/debug/DebugJdbcPage.vue | 23 ++++++++++++++++- .../components/debug/DebugTcpPage.vue | 23 ++++++++++++++++- 7 files changed, 111 insertions(+), 13 deletions(-) diff --git a/frontend/src/business/components/api/definition/ApiDefinition.vue b/frontend/src/business/components/api/definition/ApiDefinition.vue index a3d9095a71..479922971c 100644 --- a/frontend/src/business/components/api/definition/ApiDefinition.vue +++ b/frontend/src/business/components/api/definition/ApiDefinition.vue @@ -39,6 +39,7 @@ @editApi="editApi" @handleCase="handleCase" @handleEditBatch="handleEditBatch" + @showExecResult="showExecResult" ref="apiList"/> @@ -51,10 +52,10 @@
- - - - + + + +
@@ -198,8 +199,8 @@ }); this.apiDefaultTab = newTabName; }, - debug() { - this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug"); + debug(id) { + this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug",id); }, editApi(row) { let name = this.$t('api_test.definition.request.edit_api'); @@ -256,6 +257,9 @@ }, changeProtocol(data) { this.currentProtocol = data; + }, + showExecResult(row){ + this.debug(row); } } } diff --git a/frontend/src/business/components/api/definition/components/ApiCaseList.vue b/frontend/src/business/components/api/definition/components/ApiCaseList.vue index 3fbb20dad8..7f13288b18 100644 --- a/frontend/src/business/components/api/definition/components/ApiCaseList.vue +++ b/frontend/src/business/components/api/definition/components/ApiCaseList.vue @@ -66,7 +66,10 @@ -
{{getResult(item.execResult)}}
+ {{getResult(item.execResult)}} +
+
{{getResult(item.execResult)}}
+
{{item.updateTime | timestampFormatDate }} {{item.updateUser}} @@ -388,6 +391,10 @@ }, handleClose() { this.visible = false; + }, + showExecResult(row) { + this.visible = false; + this.$emit('showExecResult', row); } } } diff --git a/frontend/src/business/components/api/definition/components/ApiList.vue b/frontend/src/business/components/api/definition/components/ApiList.vue index 11687f393d..91fe6f53e9 100644 --- a/frontend/src/business/components/api/definition/components/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/ApiList.vue @@ -81,7 +81,7 @@ - +
@@ -304,6 +304,9 @@ return this.methodColorMap.get(method); } }, + showExecResult(row) { + this.$emit('showExecResult', row); + } }, } diff --git a/frontend/src/business/components/api/definition/components/debug/DebugDubboPage.vue b/frontend/src/business/components/api/definition/components/debug/DebugDubboPage.vue index bc978f726f..09152f49e0 100644 --- a/frontend/src/business/components/api/definition/components/debug/DebugDubboPage.vue +++ b/frontend/src/business/components/api/definition/components/debug/DebugDubboPage.vue @@ -46,6 +46,7 @@ props: { currentProtocol: String, scenario: Boolean, + testCase: {}, }, data() { return { @@ -66,7 +67,27 @@ } }, created() { - this.request = createComponent("DubboSampler"); + if (this.testCase) { + // 执行结果信息 + let url = "/api/definition/report/getReport/" + this.testCase.id; + this.$get(url, response => { + if (response.data) { + let data = JSON.parse(response.data.content); + this.responseData = data; + } + }); + this.request = this.testCase.request; + if (this.request) { + this.debugForm.method = this.request.method; + if (this.request.url) { + this.debugForm.url = this.request.url; + } else { + this.debugForm.url = this.request.path; + } + } + } else { + this.request = createComponent("DubboSampler"); + } }, watch: { debugResultId() { diff --git a/frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue b/frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue index 4013cdfec6..ad1404f120 100644 --- a/frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue +++ b/frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue @@ -59,6 +59,7 @@ components: {MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun}, props: { currentProtocol: String, + testCase: {}, scenario: Boolean, }, data() { @@ -79,12 +80,32 @@ } }, created() { - this.createHttp(); + if (this.testCase) { + // 执行结果信息 + let url = "/api/definition/report/getReport/" + this.testCase.id; + this.$get(url, response => { + if (response.data) { + let data = JSON.parse(response.data.content); + this.responseData = data; + } + }); + this.request = this.testCase.request; + if (this.request) { + this.debugForm.method = this.request.method; + if (this.request.url) { + this.debugForm.url = this.request.url; + } else { + this.debugForm.url = this.request.path; + } + } + } else { + this.createHttp(); + } }, watch: { debugResultId() { this.getResult() - } + }, }, methods: { handleCommand(e) { diff --git a/frontend/src/business/components/api/definition/components/debug/DebugJdbcPage.vue b/frontend/src/business/components/api/definition/components/debug/DebugJdbcPage.vue index bdc212dc8d..ad51164f1a 100644 --- a/frontend/src/business/components/api/definition/components/debug/DebugJdbcPage.vue +++ b/frontend/src/business/components/api/definition/components/debug/DebugJdbcPage.vue @@ -48,6 +48,7 @@ props: { currentProtocol: String, scenario: Boolean, + testCase: {}, }, data() { return { @@ -68,7 +69,27 @@ } }, created() { - this.request = createComponent("JDBCSampler"); + if (this.testCase) { + // 执行结果信息 + let url = "/api/definition/report/getReport/" + this.testCase.id; + this.$get(url, response => { + if (response.data) { + let data = JSON.parse(response.data.content); + this.responseData = data; + } + }); + this.request = this.testCase.request; + if (this.request) { + this.debugForm.method = this.request.method; + if (this.request.url) { + this.debugForm.url = this.request.url; + } else { + this.debugForm.url = this.request.path; + } + } + } else { + this.request = createComponent("JDBCSampler"); + } }, watch: { debugResultId() { diff --git a/frontend/src/business/components/api/definition/components/debug/DebugTcpPage.vue b/frontend/src/business/components/api/definition/components/debug/DebugTcpPage.vue index 3b7fc786ea..d81f260098 100644 --- a/frontend/src/business/components/api/definition/components/debug/DebugTcpPage.vue +++ b/frontend/src/business/components/api/definition/components/debug/DebugTcpPage.vue @@ -47,6 +47,7 @@ props: { currentProtocol: String, scenario: Boolean, + testCase: {}, }, data() { return { @@ -67,7 +68,27 @@ } }, created() { - this.request = createComponent("TCPSampler"); + if (this.testCase) { + // 执行结果信息 + let url = "/api/definition/report/getReport/" + this.testCase.id; + this.$get(url, response => { + if (response.data) { + let data = JSON.parse(response.data.content); + this.responseData = data; + } + }); + this.request = this.testCase.request; + if (this.request) { + this.debugForm.method = this.request.method; + if (this.request.url) { + this.debugForm.url = this.request.url; + } else { + this.debugForm.url = this.request.path; + } + } + } else { + this.request = createComponent("TCPSampler"); + } }, watch: { debugResultId() { From e071f33dbd9e89b9443510e8d9507a11b12c2a4e Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 11:35:30 +0800 Subject: [PATCH 08/27] =?UTF-8?q?feat(=E6=80=A7=E8=83=BD=E6=B5=8B=E8=AF=95?= =?UTF-8?q?-xPack):=20=E5=A2=9E=E5=8A=A0k8s=E8=B5=84=E6=BA=90=E6=B1=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../constants/ResourcePoolTypeEnum.java | 2 +- .../TestResourcePoolController.java | 2 - .../KubernetesResourcePoolService.java | 7 ++ .../service/NodeResourcePoolService.java | 96 +++++++++++++++++++ .../service/TestResourcePoolService.java | 73 ++------------ backend/src/main/java/io/metersphere/xpack | 2 +- .../settings/system/TestResourcePool.vue | 67 ++++++++++++- frontend/src/business/components/xpack | 2 +- 8 files changed, 180 insertions(+), 71 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/service/KubernetesResourcePoolService.java create mode 100644 backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java diff --git a/backend/src/main/java/io/metersphere/commons/constants/ResourcePoolTypeEnum.java b/backend/src/main/java/io/metersphere/commons/constants/ResourcePoolTypeEnum.java index 8707a5b61e..554549b061 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/ResourcePoolTypeEnum.java +++ b/backend/src/main/java/io/metersphere/commons/constants/ResourcePoolTypeEnum.java @@ -4,5 +4,5 @@ public enum ResourcePoolTypeEnum { /** * node controller 资源池 */ - NODE + NODE, K8S } diff --git a/backend/src/main/java/io/metersphere/controller/TestResourcePoolController.java b/backend/src/main/java/io/metersphere/controller/TestResourcePoolController.java index 3088b617b8..ad281b7ed5 100644 --- a/backend/src/main/java/io/metersphere/controller/TestResourcePoolController.java +++ b/backend/src/main/java/io/metersphere/controller/TestResourcePoolController.java @@ -2,7 +2,6 @@ package io.metersphere.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; -import io.metersphere.base.domain.TestResourcePool; import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; @@ -14,7 +13,6 @@ import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; - import java.util.List; @RequestMapping("testresourcepool") diff --git a/backend/src/main/java/io/metersphere/service/KubernetesResourcePoolService.java b/backend/src/main/java/io/metersphere/service/KubernetesResourcePoolService.java new file mode 100644 index 0000000000..a7c98b1556 --- /dev/null +++ b/backend/src/main/java/io/metersphere/service/KubernetesResourcePoolService.java @@ -0,0 +1,7 @@ +package io.metersphere.service; + +import io.metersphere.dto.TestResourcePoolDTO; + +public interface KubernetesResourcePoolService { + boolean validate(TestResourcePoolDTO testResourcePool); +} diff --git a/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java b/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java new file mode 100644 index 0000000000..5ac02b5367 --- /dev/null +++ b/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java @@ -0,0 +1,96 @@ +package io.metersphere.service; + +import com.alibaba.fastjson.JSON; +import io.metersphere.base.domain.TestResource; +import io.metersphere.base.domain.TestResourceExample; +import io.metersphere.base.mapper.TestResourceMapper; +import io.metersphere.commons.constants.ResourceStatusEnum; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; +import io.metersphere.dto.NodeDTO; +import io.metersphere.dto.TestResourcePoolDTO; +import io.metersphere.i18n.Translator; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static io.metersphere.commons.constants.ResourceStatusEnum.VALID; + +@Service +public class NodeResourcePoolService { + private final static String nodeControllerUrl = "http://%s:%s/status"; + + @Resource + private RestTemplate restTemplateWithTimeOut; + @Resource + private TestResourceMapper testResourceMapper; + + public boolean validate(TestResourcePoolDTO testResourcePool) { + if (CollectionUtils.isEmpty(testResourcePool.getResources())) { + MSException.throwException(Translator.get("no_nodes_message")); + } + + deleteTestResource(testResourcePool.getId()); + List nodeIps = testResourcePool.getResources().stream() + .map(resource -> { + NodeDTO nodeDTO = JSON.parseObject(resource.getConfiguration(), NodeDTO.class); + return nodeDTO.getIp(); + }) + .distinct() + .collect(Collectors.toList()); + if (nodeIps.size() < testResourcePool.getResources().size()) { + MSException.throwException(Translator.get("duplicate_node_ip")); + } + testResourcePool.setStatus(VALID.name()); + boolean isValid = true; + for (TestResource resource : testResourcePool.getResources()) { + NodeDTO nodeDTO = JSON.parseObject(resource.getConfiguration(), NodeDTO.class); + boolean isValidate = validateNode(nodeDTO); + if (!isValidate) { + testResourcePool.setStatus(ResourceStatusEnum.INVALID.name()); + resource.setStatus(ResourceStatusEnum.INVALID.name()); + isValid = false; + } else { + resource.setStatus(VALID.name()); + } + resource.setTestResourcePoolId(testResourcePool.getId()); + updateTestResource(resource); + } + return isValid; + } + + + private boolean validateNode(NodeDTO node) { + try { + ResponseEntity entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), String.class); + return HttpStatus.OK.equals(entity.getStatusCode()); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + return false; + } + } + + private void updateTestResource(TestResource testResource) { + testResource.setUpdateTime(System.currentTimeMillis()); + testResource.setCreateTime(System.currentTimeMillis()); + if (StringUtils.isBlank(testResource.getId())) { + testResource.setId(UUID.randomUUID().toString()); + } + // 如果是更新操作,插入与原来的ID相同的数据 + testResourceMapper.insertSelective(testResource); + } + + private void deleteTestResource(String testResourcePoolId) { + TestResourceExample testResourceExample = new TestResourceExample(); + testResourceExample.createCriteria().andTestResourcePoolIdEqualTo(testResourcePoolId); + testResourceMapper.deleteByExample(testResourceExample); + } +} diff --git a/backend/src/main/java/io/metersphere/service/TestResourcePoolService.java b/backend/src/main/java/io/metersphere/service/TestResourcePoolService.java index ce6aef6ac0..b76bd9021d 100644 --- a/backend/src/main/java/io/metersphere/service/TestResourcePoolService.java +++ b/backend/src/main/java/io/metersphere/service/TestResourcePoolService.java @@ -1,26 +1,20 @@ package io.metersphere.service; -import com.alibaba.fastjson.JSON; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.LoadTestMapper; import io.metersphere.base.mapper.TestResourceMapper; import io.metersphere.base.mapper.TestResourcePoolMapper; -import io.metersphere.commons.constants.ResourceStatusEnum; +import io.metersphere.commons.constants.ResourcePoolTypeEnum; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.LogUtil; import io.metersphere.controller.request.resourcepool.QueryResourcePoolRequest; -import io.metersphere.dto.NodeDTO; import io.metersphere.dto.TestResourcePoolDTO; import io.metersphere.i18n.Translator; import org.apache.commons.beanutils.BeanUtils; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.lang.reflect.InvocationTargetException; @@ -40,16 +34,14 @@ import static io.metersphere.commons.constants.ResourceStatusEnum.VALID; @Transactional(rollbackFor = Exception.class) public class TestResourcePoolService { - private final static String nodeControllerUrl = "http://%s:%s/status"; - @Resource private TestResourcePoolMapper testResourcePoolMapper; @Resource private TestResourceMapper testResourceMapper; @Resource - private RestTemplate restTemplateWithTimeOut; - @Resource private LoadTestMapper loadTestMapper; + @Resource + private NodeResourcePoolService nodeResourcePoolService; public TestResourcePoolDTO addTestResourcePool(TestResourcePoolDTO testResourcePool) { checkTestResourcePool(testResourcePool); @@ -168,61 +160,14 @@ public class TestResourcePoolService { } private boolean validateTestResourcePool(TestResourcePoolDTO testResourcePool) { - return validateNodes(testResourcePool); - } - - private boolean validateNodes(TestResourcePoolDTO testResourcePool) { - if (CollectionUtils.isEmpty(testResourcePool.getResources())) { - MSException.throwException(Translator.get("no_nodes_message")); - } - - deleteTestResource(testResourcePool.getId()); - List nodeIps = testResourcePool.getResources().stream() - .map(resource -> { - NodeDTO nodeDTO = JSON.parseObject(resource.getConfiguration(), NodeDTO.class); - return nodeDTO.getIp(); - }) - .distinct() - .collect(Collectors.toList()); - if (nodeIps.size() < testResourcePool.getResources().size()) { - MSException.throwException(Translator.get("duplicate_node_ip")); - } - testResourcePool.setStatus(VALID.name()); - boolean isValid = true; - for (TestResource resource : testResourcePool.getResources()) { - NodeDTO nodeDTO = JSON.parseObject(resource.getConfiguration(), NodeDTO.class); - boolean isValidate = validateNode(nodeDTO); - if (!isValidate) { - testResourcePool.setStatus(ResourceStatusEnum.INVALID.name()); - resource.setStatus(ResourceStatusEnum.INVALID.name()); - isValid = false; - } else { - resource.setStatus(VALID.name()); + if (StringUtils.equalsIgnoreCase(testResourcePool.getType(), ResourcePoolTypeEnum.K8S.name())) { + KubernetesResourcePoolService resourcePoolService = CommonBeanFactory.getBean(KubernetesResourcePoolService.class); + if (resourcePoolService == null) { + return false; } - resource.setTestResourcePoolId(testResourcePool.getId()); - updateTestResource(resource); + return resourcePoolService.validate(testResourcePool); } - return isValid; - } - - private boolean validateNode(NodeDTO node) { - try { - ResponseEntity entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), String.class); - return HttpStatus.OK.equals(entity.getStatusCode()); - } catch (Exception e) { - LogUtil.error(e.getMessage(), e); - return false; - } - } - - private void updateTestResource(TestResource testResource) { - testResource.setUpdateTime(System.currentTimeMillis()); - testResource.setCreateTime(System.currentTimeMillis()); - if (StringUtils.isBlank(testResource.getId())) { - testResource.setId(UUID.randomUUID().toString()); - } - // 如果是更新操作,插入与原来的ID相同的数据 - testResourceMapper.insertSelective(testResource); + return nodeResourcePoolService.validate(testResourcePool); } private void deleteTestResource(String testResourcePoolId) { diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index 905ca8af61..2ba1351aa0 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit 905ca8af61ce966d26109e9c5c8c0aee3ca1324e +Subproject commit 2ba1351aa0135cdf3e5de740fa2d9c185b60ce9d diff --git a/frontend/src/business/components/settings/system/TestResourcePool.vue b/frontend/src/business/components/settings/system/TestResourcePool.vue index a4d755dcff..bd323dff8e 100644 --- a/frontend/src/business/components/settings/system/TestResourcePool.vue +++ b/frontend/src/business/components/settings/system/TestResourcePool.vue @@ -12,6 +12,7 @@ @@ -52,7 +53,7 @@ :destroy-on-close="true" v-loading="result.loading" > - @@ -64,9 +65,40 @@ Node + Kubernetes
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -115,7 +147,7 @@ :title="$t('test_resource_pool.update_resource_pool')" :visible.sync="updateVisible" width="70%" :destroy-on-close="true" @close="closeFunc"> - @@ -127,9 +159,40 @@ Node + Kubernetes
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/frontend/src/business/components/xpack b/frontend/src/business/components/xpack index a22a3005d9..29a8fc0960 160000 --- a/frontend/src/business/components/xpack +++ b/frontend/src/business/components/xpack @@ -1 +1 @@ -Subproject commit a22a3005d9bd254793fcf634d72539cbdf31be3a +Subproject commit 29a8fc09602fde5708af06582ac972d98eb69836 From 469802030ca634adddc63e1b31b8df5af3f0c683 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 12:19:35 +0800 Subject: [PATCH 09/27] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E9=83=A8=E5=88=86=E7=BC=BA=E9=99=B7=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/definition/request/MsScenario.java | 3 +- .../api/service/ApiAutomationService.java | 2 +- .../api/service/ApiScenarioModuleService.java | 3 +- .../automation/scenario/AddBasisScenario.vue | 135 +++++++++--------- .../api/automation/scenario/ApiComponent.vue | 2 +- .../automation/scenario/ApiScenarioModule.vue | 1 + .../automation/scenario/EditApiScenario.vue | 9 +- .../api/automation/scenario/api/ApiList.vue | 1 + .../api/definition/components/ApiCaseList.vue | 3 + .../api/definition/components/ApiConfig.vue | 3 + .../api/definition/components/ApiList.vue | 3 + .../request/http/ApiHttpRequestForm.vue | 31 ++-- .../request/http/ApiRequestForm.vue | 6 +- frontend/src/business/components/xpack | 2 +- 14 files changed, 112 insertions(+), 92 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java index 6be0d1fe99..92290a861e 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java @@ -17,6 +17,7 @@ import io.metersphere.commons.utils.CommonBeanFactory; import lombok.Data; import lombok.EqualsAndHashCode; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.save.SaveService; import org.apache.jmeter.testelement.TestElement; import org.apache.jorphan.collections.HashTree; @@ -47,7 +48,7 @@ public class MsScenario extends MsTestElement { if (!this.isEnable()) { return; } - if (environmentId != null) { + if (StringUtils.isNotEmpty(environmentId)) { ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class); ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId); config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class)); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 498e178e37..70145ccad2 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -124,7 +124,7 @@ public class ApiAutomationService { scenario.setDescription(request.getDescription()); apiScenarioMapper.insert(scenario); - List bodyUploadIds = new ArrayList<>(request.getBodyUploadIds()); + List bodyUploadIds = request.getBodyUploadIds(); apiDefinitionService.createBodyFiles(bodyUploadIds, bodyFiles); } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java index ffbdb54759..24d2c3412b 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java @@ -21,11 +21,10 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.annotation.Resource; import java.util.*; import java.util.stream.Collectors; -import javax.annotation.Resource; - @Service @Transactional(rollbackFor = Exception.class) public class ApiScenarioModuleService { diff --git a/frontend/src/business/components/api/automation/scenario/AddBasisScenario.vue b/frontend/src/business/components/api/automation/scenario/AddBasisScenario.vue index 3b826f7de1..8ef356a85e 100644 --- a/frontend/src/business/components/api/automation/scenario/AddBasisScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/AddBasisScenario.vue @@ -57,74 +57,75 @@ diff --git a/frontend/src/business/components/api/automation/scenario/ApiComponent.vue b/frontend/src/business/components/api/automation/scenario/ApiComponent.vue index 6b35d98651..8056137ced 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiComponent.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiComponent.vue @@ -41,7 +41,7 @@

{{$t('api_test.definition.request.req_param')}}

- + diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue index 47dc95d5a4..1f728d338d 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue @@ -265,6 +265,7 @@ const children = parent.data.children || parent.data const index = children.findIndex(d => d.id !== undefined && data.id !== undefined && d.id === data.id) children.splice(index, 1); + this.getApiModuleTree(); }); }, diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index 9d629a8cba..ab484774bd 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -476,7 +476,7 @@ request.enable === undefined ? request.enable = true : request.enable; request.active = false; request.resourceId = getUUID(); - if (referenced === 'REF') { + if (referenced === 'REF' || !request.hashTree) { request.hashTree = []; } if (this.selectedTreeNode != undefined) { @@ -496,7 +496,7 @@ request.enable === undefined ? request.enable = true : request.enable; request.active = false; request.resourceId = getUUID(); - if (referenced === 'REF') { + if (referenced === 'REF' || !request.hashTree) { request.hashTree = []; } if (this.selectedTreeNode != undefined) { @@ -506,6 +506,8 @@ } }) this.apiListVisible = false; + this.currentRow.cases = []; + this.currentRow.apis = []; this.sort(); this.reload(); }, @@ -861,7 +863,8 @@ /deep/ .el-step__icon.is-text { border: 1px solid; } - /deep/.el-drawer__header{ + + /deep/ .el-drawer__header { margin-bottom: 0px; } diff --git a/frontend/src/business/components/api/automation/scenario/api/ApiList.vue b/frontend/src/business/components/api/automation/scenario/api/ApiList.vue index a4102bb1df..9227f02246 100644 --- a/frontend/src/business/components/api/automation/scenario/api/ApiList.vue +++ b/frontend/src/business/components/api/automation/scenario/api/ApiList.vue @@ -193,6 +193,7 @@ this.total = response.data.itemCount; this.tableData = response.data.listObject; }); + this.selectRows = new Set(); }, handleSelect(selection, row) { row.hashTree = []; diff --git a/frontend/src/business/components/api/definition/components/ApiCaseList.vue b/frontend/src/business/components/api/definition/components/ApiCaseList.vue index 7f13288b18..7ca0bb37c6 100644 --- a/frontend/src/business/components/api/definition/components/ApiCaseList.vue +++ b/frontend/src/business/components/api/definition/components/ApiCaseList.vue @@ -335,6 +335,9 @@ for (let index in response.data) { let test = response.data[index]; test.request = JSON.parse(test.request); + if (!test.request.hashTree) { + test.request.hashTree = []; + } } this.apiCaseList = response.data; if (this.apiCaseList.length == 0) { diff --git a/frontend/src/business/components/api/definition/components/ApiConfig.vue b/frontend/src/business/components/api/definition/components/ApiConfig.vue index 1df8d46921..b886bf9d60 100644 --- a/frontend/src/business/components/api/definition/components/ApiConfig.vue +++ b/frontend/src/business/components/api/definition/components/ApiConfig.vue @@ -77,6 +77,9 @@ } else { this.reqUrl = "/api/definition/create"; } + if (!this.request.hashTree) { + this.request.hashTree = []; + } }, methods: { runTest(data) { diff --git a/frontend/src/business/components/api/definition/components/ApiList.vue b/frontend/src/business/components/api/definition/components/ApiList.vue index 91fe6f53e9..498fb5c9e9 100644 --- a/frontend/src/business/components/api/definition/components/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/ApiList.vue @@ -275,6 +275,9 @@ handleTestCase(api) { this.selectApi = api; let request = JSON.parse(api.request); + if (!request.hashTree) { + request.hashTree = []; + } this.selectApi.url = request.path; this.$refs.caseList.open(this.selectApi); }, diff --git a/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue b/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue index d89b29472b..279badcc10 100644 --- a/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue +++ b/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue @@ -2,7 +2,7 @@ -
+
@@ -58,23 +58,23 @@
- -
- - - - - - - - - +
+
+ + + + + + + + +
- + +{{$t('api_test.definition.request.pre_script')}}
+{{$t('api_test.definition.request.post_script')}} @@ -116,6 +116,7 @@ return []; } }, + referenced: Boolean, isShowEnable: Boolean, jsonPathList: Array, isReadOnly: { diff --git a/frontend/src/business/components/api/definition/components/request/http/ApiRequestForm.vue b/frontend/src/business/components/api/definition/components/request/http/ApiRequestForm.vue index 3a5af1910c..de97afb499 100644 --- a/frontend/src/business/components/api/definition/components/request/http/ApiRequestForm.vue +++ b/frontend/src/business/components/api/definition/components/request/http/ApiRequestForm.vue @@ -1,6 +1,6 @@ @@ -17,6 +17,10 @@ type: Boolean, default: true }, + referenced: { + type: Boolean, + default: false + }, isReadOnly: { type: Boolean, default: false diff --git a/frontend/src/business/components/xpack b/frontend/src/business/components/xpack index a22a3005d9..29a8fc0960 160000 --- a/frontend/src/business/components/xpack +++ b/frontend/src/business/components/xpack @@ -1 +1 @@ -Subproject commit a22a3005d9bd254793fcf634d72539cbdf31be3a +Subproject commit 29a8fc09602fde5708af06582ac972d98eb69836 From 1efe5b0c2df147b44c135f78516a12468539ec89 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 14:35:32 +0800 Subject: [PATCH 10/27] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E9=83=A8=E5=88=86=E7=BC=BA=E9=99=B7=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ApiAutomationController.java | 5 ++++ .../controller/ApiDefinitionController.java | 5 ++++ .../api/dto/automation/ApiScenarioDTO.java | 4 ++- .../api/service/ApiAutomationService.java | 28 ++++++++++++------- .../api/service/ApiDefinitionService.java | 4 +++ .../mapper/ext/ExtApiDefinitionMapper.java | 2 ++ .../mapper/ext/ExtApiDefinitionMapper.xml | 11 ++++++++ .../base/mapper/ext/ExtApiScenarioMapper.java | 3 ++ .../base/mapper/ext/ExtApiScenarioMapper.xml | 20 +++++++++++++ backend/src/main/java/io/metersphere/xpack | 2 +- .../api/automation/scenario/AddTag.vue | 4 +-- .../automation/scenario/ApiScenarioList.vue | 12 ++++---- .../automation/scenario/EditApiScenario.vue | 9 +++--- .../automation/scenario/ImportApiScenario.vue | 2 +- .../api/definition/components/ApiList.vue | 6 ++-- .../api/definition/components/ApiModule.vue | 1 + 16 files changed, 89 insertions(+), 29 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java index f4452ed120..710f2d3aa3 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java @@ -58,6 +58,11 @@ public class ApiAutomationController { apiAutomationService.removeToGc(ids); } + @PostMapping("/reduction") + public void reduction(@RequestBody List ids) { + apiAutomationService.reduction(ids); + } + @GetMapping("/getApiScenario/{id}") public ApiScenario getScenarioDefinition(@PathVariable String id) { return apiAutomationService.getApiScenario(id); diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java index b27b4737b6..354f37d5e8 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java @@ -64,6 +64,11 @@ public class ApiDefinitionController { apiDefinitionService.removeToGc(ids); } + @PostMapping("/reduction") + public void reduction(@RequestBody List ids) { + apiDefinitionService.reduction(ids); + } + @GetMapping("/get/{id}") public ApiDefinition get(@PathVariable String id) { return apiDefinitionService.get(id); diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioDTO.java b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioDTO.java index 173f7897da..efecbd4e2b 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioDTO.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioDTO.java @@ -4,11 +4,13 @@ import io.metersphere.base.domain.ApiScenario; import lombok.Getter; import lombok.Setter; +import java.util.List; + @Getter @Setter public class ApiScenarioDTO extends ApiScenario { private String projectName; private String userName; - private String tagName; + private List tagNames; } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 70145ccad2..9d652d367f 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -22,6 +22,7 @@ import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.i18n.Translator; import io.metersphere.track.dto.TestPlanDTO; @@ -67,11 +68,12 @@ public class ApiAutomationService { private static final String BODY_FILE_DIR = "/opt/metersphere/data/body"; public List list(ApiScenarioRequest request) { + request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); + List list = extApiScenarioMapper.list(request); ApiTagExample example = new ApiTagExample(); example.createCriteria().andProjectIdEqualTo(request.getProjectId()); List tags = apiTagMapper.selectByExample(example); Map tagMap = tags.stream().collect(Collectors.toMap(ApiTag::getId, ApiTag::getName)); - List list = extApiScenarioMapper.list(request); Gson gs = new Gson(); list.forEach(item -> { if (item.getTagId() != null) { @@ -81,7 +83,11 @@ public class ApiAutomationService { buf.append(","); }); if (buf != null && buf.length() > 0) { - item.setTagName(buf.toString().substring(0, buf.toString().length() - 1)); + String tagNames = buf.toString().substring(0, buf.toString().length() - 1); + List tagList = Arrays.asList(tagNames.split(",")); + item.setTagNames(tagList); + } else { + item.setTagNames(new ArrayList<>()); } } }); @@ -166,12 +172,12 @@ public class ApiAutomationService { apiScenarioMapper.deleteByExample(example); } - public void removeToGc(List ids) { - ApiScenario record = new ApiScenario(); - record.setStatus(ScenarioStatus.Trash.name()); - ApiScenarioExample example = new ApiScenarioExample(); - example.createCriteria().andIdIn(ids); - apiScenarioMapper.updateByExampleSelective(record, example); + public void removeToGc(List apiIds) { + extApiScenarioMapper.removeToGc(apiIds); + } + + public void reduction(List apiIds) { + extApiScenarioMapper.reduction(apiIds); } private void checkNameExist(SaveApiScenarioRequest request) { @@ -244,12 +250,14 @@ public class ApiAutomationService { // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 if (StringUtils.isNotEmpty(element.getString("hashTree"))) { LinkedList elements = mapper.readValue(element.getString("hashTree"), - new TypeReference>() {}); + new TypeReference>() { + }); scenario.setHashTree(elements); } if (StringUtils.isNotEmpty(element.getString("variables"))) { LinkedList variables = mapper.readValue(element.getString("variables"), - new TypeReference>() {}); + new TypeReference>() { + }); scenario.setVariables(variables); } LinkedList scenarios = new LinkedList<>(); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 5851ca24ec..a1c60272fa 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -163,6 +163,10 @@ public class ApiDefinitionService { extApiDefinitionMapper.removeToGc(apiIds); } + public void reduction(List apiIds) { + extApiDefinitionMapper.reduction(apiIds); + } + public void deleteBodyFiles(String apiId) { File file = new File(BODY_FILE_DIR + "/" + apiId); FileUtil.deleteContents(file); diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java index 320d5b4664..ba560aeebe 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java @@ -15,4 +15,6 @@ public interface ExtApiDefinitionMapper { int removeToGc(@Param("ids") List ids); + int reduction(@Param("ids") List ids); + } \ No newline at end of file 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 ab5b4dac15..545bc9b71a 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 @@ -255,4 +255,15 @@ #{v} + + + update api_definition + set + status = 'Underway' + where id in + + #{v} + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java index bec0fbde89..fce72e2e7b 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java @@ -16,4 +16,7 @@ public interface ExtApiScenarioMapper { List selectReference(@Param("request") ApiScenarioRequest request); + int removeToGc(@Param("ids") List ids); + + int reduction(@Param("ids") List ids); } 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 da36ff4df5..e7c638e10c 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 @@ -88,5 +88,25 @@ + + update api_scenario + set + status = 'Trash' + where id in + + #{v} + + + + + update api_scenario + set + status = 'Underway' + where id in + + #{v} + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index 2ba1351aa0..905ca8af61 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit 2ba1351aa0135cdf3e5de740fa2d9c185b60ce9d +Subproject commit 905ca8af61ce966d26109e9c5c8c0aee3ca1324e diff --git a/frontend/src/business/components/api/automation/scenario/AddTag.vue b/frontend/src/business/components/api/automation/scenario/AddTag.vue index 4c78077330..4bb4dd12dd 100644 --- a/frontend/src/business/components/api/automation/scenario/AddTag.vue +++ b/frontend/src/business/components/api/automation/scenario/AddTag.vue @@ -9,7 +9,7 @@
- {{$t('commons.save')}} + {{$t('commons.save')}} @@ -72,7 +72,7 @@ }, methods: { saveTag() { - if (this.tagData.id != undefined && this.tagForm.id != null) { + if (this.tagForm.id != undefined && this.tagForm.id != null) { this.path = "/api/tag/update"; } else { this.path = "/api/tag/create"; diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index 7214df3c1c..16c40b99d9 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -25,9 +25,11 @@ - + @@ -210,8 +212,8 @@ this.$emit('edit', row); }, reductionApi(row) { - let obj = {id: row.id, projectId: row.projectId, name: row.name, status: 'Underway'} - this.$fileUpload("/api/automation/update", null, [], obj, () => { + let obj = [row.id]; + this.$post("/api/automation/reduction", obj, response => { this.$success(this.$t('commons.save_success')); this.search(); }) @@ -265,7 +267,7 @@ diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index ab484774bd..ea19ba2c39 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -352,6 +352,9 @@ } }, created() { + if (!this.currentScenario.apiScenarioModuleId) { + this.currentScenario.apiScenarioModuleId = ""; + } this.projectId = getCurrentProjectID(); this.operatingElements = ELEMENTS.get("ALL"); this.getMaintainerOptions(); @@ -450,7 +453,7 @@ this.reload(); }, addScenario(arr) { - if (arr.length > 0) { + if (arr && arr.length > 0) { arr.forEach(item => { item.enable === undefined ? item.enable = true : item.enable; this.scenarioDefinition.push(item); @@ -710,10 +713,6 @@ } }, setParameter() { - this.currentScenario.projectId = this.projectId; - if (!this.currentScenario.id) { - this.currentScenario.id = getUUID(); - } this.currentScenario.stepTotal = this.scenarioDefinition.length; this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId); // 构建一个场景对象 方便引用处理 diff --git a/frontend/src/business/components/api/automation/scenario/ImportApiScenario.vue b/frontend/src/business/components/api/automation/scenario/ImportApiScenario.vue index 01c1ab5daa..6ef476bc3a 100644 --- a/frontend/src/business/components/api/automation/scenario/ImportApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/ImportApiScenario.vue @@ -68,7 +68,7 @@ if (response.data) { response.data.forEach(item => { let scenarioDefinition = JSON.parse(item.scenarioDefinition); - let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition}; + let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition.hashTree}; scenarios.push(obj); }) this.$emit('addScenario', scenarios); diff --git a/frontend/src/business/components/api/definition/components/ApiList.vue b/frontend/src/business/components/api/definition/components/ApiList.vue index 498fb5c9e9..16bc90da52 100644 --- a/frontend/src/business/components/api/definition/components/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/ApiList.vue @@ -230,10 +230,8 @@ this.$emit('editApi', row); }, reductionApi(row) { - row.status = 'Underway'; - row.request = null; - row.response = null; - this.$fileUpload("/api/definition/update", null, [], row, () => { + let ids = [row.id]; + this.$post('/api/definition/reduction/', ids, () => { this.$success(this.$t('commons.save_success')); this.search(); }); diff --git a/frontend/src/business/components/api/definition/components/ApiModule.vue b/frontend/src/business/components/api/definition/components/ApiModule.vue index 812732eab1..aea697aa4a 100644 --- a/frontend/src/business/components/api/definition/components/ApiModule.vue +++ b/frontend/src/business/components/api/definition/components/ApiModule.vue @@ -138,6 +138,7 @@ if (this.expandedNode.length === 0) { this.expandedNode.push("root"); } + this.nextFlag = true; this.result = this.$get("/api/module/list/" + this.projectId + "/" + this.protocol, response => { if (response.data != undefined && response.data != null) { this.data[1].children = response.data; From 60fc50cf07839ccbed1c408e7b7219ac7651b015 Mon Sep 17 00:00:00 2001 From: BugKing Date: Mon, 14 Dec 2020 15:02:45 +0800 Subject: [PATCH 11/27] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20roadmap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ROADMAP.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index a6d51bbbb4..440f6fdbc5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -55,11 +55,17 @@ - [x] 测试跟踪:支持对接禅道同步缺陷 - [x] 其他:Jenkins 插件支持 pipeline 方式调用 +## v1.6 (开发中) +- [ ] 新增接口管理功能 +- [ ] 全新接口自动化使用方式 +- [ ] 测试跟踪测试计划分类型展示 +- [ ] 优化消息通知配置及实现方式 + ## 规划中 - [ ] 接口测试支持添加 WebSocket 协议请求 -- [ ] 接口管理功能 - [ ] 集成云平台动态管理测试资源池 -- [ ] 支持 K8s 集群作为测试资源池 +- [ ] 测试跟踪测试用例及接口测试增加版本管理 +- [ ] 测试跟踪测试用例增加思维导图展示形式 - [ ] 移动端测试支持 - [ ] UI 功能测试支持 From 723d5aa4623d2809a8cc551c153a6ab0c0255a9e Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 15:38:38 +0800 Subject: [PATCH 12/27] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BC=80?= =?UTF-8?q?=E6=BA=90=E7=89=88=E6=98=BE=E7=A4=BA=E5=9B=BE=E7=89=87=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 10 +++ .../service/BaseDisplayService.java | 72 +++++++++++++++++++ backend/src/main/java/io/metersphere/xpack | 2 +- 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/io/metersphere/service/BaseDisplayService.java diff --git a/backend/src/main/java/io/metersphere/controller/LoginController.java b/backend/src/main/java/io/metersphere/controller/LoginController.java index f1473d15fc..a3a73e2577 100644 --- a/backend/src/main/java/io/metersphere/controller/LoginController.java +++ b/backend/src/main/java/io/metersphere/controller/LoginController.java @@ -5,14 +5,17 @@ import io.metersphere.commons.constants.UserSource; import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.LoginRequest; +import io.metersphere.service.BaseDisplayService; import io.metersphere.service.UserService; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.env.Environment; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.io.IOException; @RestController @RequestMapping @@ -22,6 +25,8 @@ public class LoginController { private UserService userService; @Resource private Environment env; + @Resource + private BaseDisplayService baseDisplayService; @GetMapping(value = "/isLogin") public ResultHolder isLogin() { @@ -66,4 +71,9 @@ public class LoginController { public String getDefaultLanguage() { return userService.getDefaultLanguage(); } + + @GetMapping("display/file/{imageName}") + public ResponseEntity image(@PathVariable("imageName") String imageName) throws IOException { + return baseDisplayService.getImage(imageName); + } } diff --git a/backend/src/main/java/io/metersphere/service/BaseDisplayService.java b/backend/src/main/java/io/metersphere/service/BaseDisplayService.java new file mode 100644 index 0000000000..6373548114 --- /dev/null +++ b/backend/src/main/java/io/metersphere/service/BaseDisplayService.java @@ -0,0 +1,72 @@ +package io.metersphere.service; + +import io.metersphere.base.domain.SystemParameter; +import io.metersphere.base.domain.SystemParameterExample; +import io.metersphere.base.mapper.SystemParameterMapper; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.List; + +@Service +public class BaseDisplayService { + @Resource + private SystemParameterMapper systemParameterMapper; + @Resource + private FileService fileService; + + public List getParamList(String type) { + SystemParameterExample example = new SystemParameterExample(); + example.createCriteria().andParamKeyLike(type + "%"); + return systemParameterMapper.selectByExample(example); + } + + public byte[] loadFileAsBytes(String fileId) { + return fileService.loadFileAsBytes(fileId); + } + + public ResponseEntity getImage(String imageName) throws IOException { + byte[] bytes = null; + List paramList = getParamList("ui." + imageName); + if (!CollectionUtils.isEmpty(paramList)) { + SystemParameter sp = paramList.get(0); + String paramValue = sp.getParamValue(); + if (StringUtils.isNotBlank(paramValue)) { + bytes = loadFileAsBytes(paramValue); + } + } + + MediaType contentType = MediaType.parseMediaType("application/octet-stream"); + if (bytes == null) { + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader()); + switch (imageName) { + case "logo": + bytes = IOUtils.toByteArray(resolver.getResources("/static/img/logo-light-MeterSphere.*.svg")[0].getInputStream()); + contentType = MediaType.valueOf("image/svg+xml"); + break; + case "loginImage": + bytes = IOUtils.toByteArray(resolver.getResources("/static/img/info.*.png")[0].getInputStream()); + break; + case "loginLogo": + bytes = IOUtils.toByteArray(resolver.getResources("/static/img/logo-dark-MeterSphere.*.svg")[0].getInputStream()); + contentType = MediaType.valueOf("image/svg+xml"); + break; + default: + break; + } + } + + return ResponseEntity.ok() + .contentType(contentType) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + imageName + "\"") + .body(bytes); + } +} diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index 2ba1351aa0..f514243111 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit 2ba1351aa0135cdf3e5de740fa2d9c185b60ce9d +Subproject commit f514243111c3acb317e80da23857143857a53566 From 2f99251debeff346995f04d6c6e967246076a505 Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 15:57:56 +0800 Subject: [PATCH 13/27] =?UTF-8?q?fix:=20=E9=81=BF=E5=85=8D=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=89=93=E5=8C=85=E7=BC=BA=E5=B0=91=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/login/Login.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/login/Login.vue b/frontend/src/login/Login.vue index 1a802e9d2c..cae9162e76 100644 --- a/frontend/src/login/Login.vue +++ b/frontend/src/login/Login.vue @@ -264,6 +264,10 @@ export default { .login-logo { background: url(../assets/logo-dark-MeterSphere.svg); } + +.logo-header { + background: url(../assets/logo-light-MeterSphere.svg); +} diff --git a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue index 1b2ba625bb..3d307e5a0e 100644 --- a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue +++ b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue @@ -236,7 +236,7 @@ let hasEnvironment = false; for (let i in this.environments) { if (this.environments[i].id === this.api.environmentId) { - this.api.environmentId = this.environments[i]; + this.api.environmentId = this.environments[i].id; hasEnvironment = true; break; } From f10b154a8ab96da0c49fec27674879b4a70a2027 Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 16:14:45 +0800 Subject: [PATCH 15/27] =?UTF-8?q?fix:=20=E6=8C=87=E5=AE=9A=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E7=9A=84=20rest=20template?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/metersphere/service/NodeResourcePoolService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java b/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java index 5ac02b5367..b22c00f9c2 100644 --- a/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java +++ b/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java @@ -28,7 +28,7 @@ import static io.metersphere.commons.constants.ResourceStatusEnum.VALID; public class NodeResourcePoolService { private final static String nodeControllerUrl = "http://%s:%s/status"; - @Resource + @Resource(name = "restTemplateWithTimeOut") private RestTemplate restTemplateWithTimeOut; @Resource private TestResourceMapper testResourceMapper; From 3af1825a26c5d0b1799051d4b2c9301b2195a6c7 Mon Sep 17 00:00:00 2001 From: shiziyuan9527 Date: Mon, 14 Dec 2020 16:17:45 +0800 Subject: [PATCH 16/27] =?UTF-8?q?feat:=20=E5=88=87=E6=8D=A2=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=90=8E=E6=98=BE=E7=A4=BA=E9=A1=B9=E7=9B=AE=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/api/head/ApiHeaderMenus.vue | 9 ++- .../components/common/head/SearchList.vue | 55 ++++++++++++++----- .../head/PerformanceHeaderMenus.vue | 16 ++++-- .../track/head/TrackHeaderMenus.vue | 13 +++-- 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/frontend/src/business/components/api/head/ApiHeaderMenus.vue b/frontend/src/business/components/api/head/ApiHeaderMenus.vue index b4dcf3f51b..409e7409d4 100644 --- a/frontend/src/business/components/api/head/ApiHeaderMenus.vue +++ b/frontend/src/business/components/api/head/ApiHeaderMenus.vue @@ -6,8 +6,12 @@ - - + + @@ -108,6 +112,7 @@ export default { isProjectActivation: true, isRouterAlive: true, apiTestProjectPath: '', + currentProject: '' } }, // watch: { diff --git a/frontend/src/business/components/common/head/SearchList.vue b/frontend/src/business/components/common/head/SearchList.vue index b6f3c3ba2c..e4effd6cbe 100644 --- a/frontend/src/business/components/common/head/SearchList.vue +++ b/frontend/src/business/components/common/head/SearchList.vue @@ -2,7 +2,7 @@
@@ -16,8 +16,8 @@
@@ -32,7 +32,8 @@ import {PROJECT_ID, ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "@ export default { name: "SearchList", props: { - options: Object + options: Object, + currentProject: String }, mounted() { this.init(); @@ -41,44 +42,68 @@ export default { return { result: {}, items: [], - search_text: '', + searchArray: [], + searchString: '', userId: getCurrentUser().id, currentProjectId: localStorage.getItem(PROJECT_ID) } }, watch: { - search_text(val) { - if (!val) { - this.init(); - } else { - this.search(); - } + searchString(val) { + this.query(val) } }, methods: { init: function () { if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) { - this.result = this.$get(this.options.url, (response) => { + this.result = this.$get("/project/listAll", response => { this.items = response.data; - this.items = this.items.splice(0, 3); + this.searchArray = response.data; if (!getCurrentProjectID() && this.items.length > 0) { this.change(this.items[0].id); } - }); + let projectId = getCurrentProjectID(); + this.changeProjectName(projectId); + }) } }, search() { if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) { - this.result = this.$post("/project/search", {name: this.search_text},response => { + this.result = this.$post("/project/search", {name: this.searchString},response => { this.items = response.data; }) } }, + query(queryString) { + this.items = queryString ? this.searchArray.filter(this.createFilter(queryString)) : this.searchArray; + }, + createFilter(queryString) { + return item => { + return (item.name.toLowerCase().indexOf(queryString.toLowerCase()) !== -1); + }; + }, change(projectId) { this.$post("/user/update/current", {id: this.userId, lastProjectId: projectId}, () => { localStorage.setItem(PROJECT_ID, projectId); - window.location.reload(); + if (this.$route.path.indexOf('/track/review/view/') >= 0) { + this.$router.replace('/track/review/all'); + } else if (this.$route.path.indexOf('/track/plan/view/') >= 0) { + this.$router.replace('/track/plan/all'); + } else { + window.location.reload(); + } + this.changeProjectName(projectId); }); + }, + changeProjectName(projectId) { + if (projectId) { + let project = this.searchArray.filter(p => p.id === projectId); + if (project.length > 0) { + this.$emit("update:currentProject", project[0].name); + } + } else { + this.$emit("update:currentProject", '选择项目'); + } } } } diff --git a/frontend/src/business/components/performance/head/PerformanceHeaderMenus.vue b/frontend/src/business/components/performance/head/PerformanceHeaderMenus.vue index 79324356fb..e63010aaec 100644 --- a/frontend/src/business/components/performance/head/PerformanceHeaderMenus.vue +++ b/frontend/src/business/components/performance/head/PerformanceHeaderMenus.vue @@ -1,13 +1,17 @@ @@ -98,7 +102,7 @@ export default { router(item) { } }, - input2: '' + currentProject: '' } }, methods: { diff --git a/frontend/src/business/components/track/head/TrackHeaderMenus.vue b/frontend/src/business/components/track/head/TrackHeaderMenus.vue index 3ac4dc779d..7f01d57323 100644 --- a/frontend/src/business/components/track/head/TrackHeaderMenus.vue +++ b/frontend/src/business/components/track/head/TrackHeaderMenus.vue @@ -2,13 +2,17 @@ @@ -78,6 +82,7 @@ export default { testCaseReviewEditPath: '', testCaseProjectPath: '', isProjectActivation: true, + currentProject: '', projectRecent: { title: this.$t('project.recent'), url: "/project/recent/5", From 82248b22daea8fc3900f2cfb8cacb79d508d0e7e Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 16:57:42 +0800 Subject: [PATCH 17/27] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E4=BF=AE=E6=94=B9Tree=20=E6=A0=B7=E5=BC=8F=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/service/ApiScenarioModuleService.java | 9 +-- .../automation/scenario/ApiScenarioModule.vue | 11 ++-- .../api/definition/components/ApiModule.vue | 58 +++++++++---------- 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java index 24d2c3412b..374f6a8c58 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java @@ -123,16 +123,17 @@ public class ApiScenarioModuleService { } } - private List queryByModuleIds(List nodeIds) { + private List queryByModuleIds(DragApiScenarioModuleRequest request) { ApiScenarioRequest apiScenarioRequest = new ApiScenarioRequest(); - apiScenarioRequest.setModuleIds(nodeIds); + apiScenarioRequest.setProjectId(request.getProjectId()); + apiScenarioRequest.setModuleIds(request.getNodeIds()); return apiAutomationService.list(apiScenarioRequest); } public int editNode(DragApiScenarioModuleRequest request) { request.setUpdateTime(System.currentTimeMillis()); checkApiScenarioModuleExist(request); - List apiScenarios = queryByModuleIds(request.getNodeIds()); + List apiScenarios = queryByModuleIds(request); apiScenarios.forEach(apiScenario -> { StringBuilder path = new StringBuilder(apiScenario.getModulePath()); @@ -171,7 +172,7 @@ public class ApiScenarioModuleService { List nodeIds = request.getNodeIds(); - List apiScenarios = queryByModuleIds(nodeIds); + List apiScenarios = queryByModuleIds(request); ApiScenarioModuleDTO nodeTree = request.getNodeTree(); diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue index 1f728d338d..edbd91f712 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue @@ -30,11 +30,9 @@ class="ms-el-input" size="mini"> - - - - - + + + - + -
- - - -
- + + + i { - color: #409eff; - margin: 0px 5px; - } - /deep/ .el-tree-node__content { height: 33px; } @@ -503,4 +477,26 @@ width: 90px; } + .father .child { + display: none; + } + + .father:hover .child { + display: block; + } + + .node-title { + width: 0px; + text-overflow: ellipsis; + white-space: nowrap; + flex: 1 1 auto; + padding: 0px 5px; + overflow: hidden; + } + + .node-operate > i { + color: #409eff; + margin: 0px 5px; + } + From a5a8f94cbede7ad8296af36863babce1b741230a Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 17:00:51 +0800 Subject: [PATCH 18/27] =?UTF-8?q?fix:=20=E6=8C=87=E5=AE=9A=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E7=9A=84=20rest=20template?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/java/io/metersphere/xpack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index f514243111..1fe20ba15a 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit f514243111c3acb317e80da23857143857a53566 +Subproject commit 1fe20ba15a7ca3fe9f77ddf866021e7c7dfe5969 From 36acba4121a766948a517a34b707cccddb6efb5c Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 17:16:56 +0800 Subject: [PATCH 19/27] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E4=BF=AE=E5=A4=8D=E6=89=A7=E8=A1=8C=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/java/io/metersphere/xpack | 2 +- .../components/api/definition/components/Run.vue | 6 +++++- .../api/definition/components/case/ApiCaseHeader.vue | 11 +---------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index f514243111..905ca8af61 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit f514243111c3acb317e80da23857143857a53566 +Subproject commit 905ca8af61ce966d26109e9c5c8c0aee3ca1324e diff --git a/frontend/src/business/components/api/definition/components/Run.vue b/frontend/src/business/components/api/definition/components/Run.vue index 887ebe2631..b44e83bfd3 100644 --- a/frontend/src/business/components/api/definition/components/Run.vue +++ b/frontend/src/business/components/api/definition/components/Run.vue @@ -104,10 +104,14 @@ threadGroup.hashTree = []; testPlan.hashTree = [threadGroup]; this.runData.forEach(item => { + if (!item.useEnvironment) { + this.$error(this.$t("api_test.environment.select_environment")); + this.$emit('runRefresh', {}); + return; + } threadGroup.hashTree.push(item); }) let reqObj = {id: this.reportId, testElement: testPlan}; - let bodyFiles = this.getBodyUploadFiles(reqObj); let url = ""; if (this.debug) { 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 8fe0bef3d9..7967a0ce89 100644 --- a/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue +++ b/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue @@ -103,6 +103,7 @@ } }, created() { + this.environment = undefined; this.getEnvironments(); }, watch: { @@ -118,16 +119,6 @@ this.environments.forEach(environment => { parseEnvironment(environment); }); - let hasEnvironment = false; - for (let i in this.environments) { - if (this.environments[i].id === this.api.environmentId) { - hasEnvironment = true; - break; - } - } - if (!hasEnvironment) { - this.environment = undefined; - } }); } else { this.environment = undefined; From fd3c8052fc2e5745f6a14758452990c14a1b2503 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 17:35:16 +0800 Subject: [PATCH 20/27] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E4=BF=AE=E5=A4=8D=E6=89=A7=E8=A1=8C=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/metersphere/api/service/ApiAutomationService.java | 2 +- .../components/api/automation/scenario/EditApiScenario.vue | 4 ++++ .../components/api/definition/components/ApiList.vue | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 9d652d367f..90c436f519 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -248,7 +248,7 @@ public class ApiAutomationService { JSONObject element = JSON.parseObject(item.getScenarioDefinition()); MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class); // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 - if (StringUtils.isNotEmpty(element.getString("hashTree"))) { + if (element!= null && StringUtils.isNotEmpty(element.getString("hashTree"))) { LinkedList elements = mapper.readValue(element.getString("hashTree"), new TypeReference>() { }); diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index ea19ba2c39..79d369b596 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -455,6 +455,10 @@ addScenario(arr) { if (arr && arr.length > 0) { arr.forEach(item => { + if (item.id === this.currentScenario.id) { + this.$error("不能引用或复制自身!"); + return; + } item.enable === undefined ? item.enable = true : item.enable; this.scenarioDefinition.push(item); }) diff --git a/frontend/src/business/components/api/definition/components/ApiList.vue b/frontend/src/business/components/api/definition/components/ApiList.vue index 4862905580..4c831ab263 100644 --- a/frontend/src/business/components/api/definition/components/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/ApiList.vue @@ -306,7 +306,12 @@ }, handleTestCase(api) { this.selectApi = api; - let request = JSON.parse(api.request); + let request = {}; + if (Object.prototype.toString.call(api.request).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') { + request = api.request; + } else { + request = JSON.parse(api.request); + } if (!request.hashTree) { request.hashTree = []; } From 80a652813f71e30e1a665a0850e47d168f1abfac Mon Sep 17 00:00:00 2001 From: shiziyuan9527 Date: Mon, 14 Dec 2020 17:43:57 +0800 Subject: [PATCH 21/27] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E9=A1=B9=E7=9B=AE=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/head/HeaderOrgWs.vue | 17 ++++++++++------- .../components/common/head/SearchList.vue | 17 +++++++++++++++-- .../components/settings/SettingMenu.vue | 2 +- frontend/src/common/js/utils.js | 1 - 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/frontend/src/business/components/common/head/HeaderOrgWs.vue b/frontend/src/business/components/common/head/HeaderOrgWs.vue index d91a800ecc..5b8a565245 100644 --- a/frontend/src/business/components/common/head/HeaderOrgWs.vue +++ b/frontend/src/business/components/common/head/HeaderOrgWs.vue @@ -26,13 +26,14 @@