Merge branch 'master' into local-api-delimit
# Conflicts: # backend/src/main/resources/i18n/messages_en_US.properties # backend/src/main/resources/i18n/messages_zh_CN.properties # backend/src/main/resources/i18n/messages_zh_TW.properties # frontend/src/business/components/api/test/ApiTestConfig.vue
This commit is contained in:
commit
e008baaf2e
|
@ -31,3 +31,4 @@ target
|
||||||
.project
|
.project
|
||||||
.classpath
|
.classpath
|
||||||
.jython_cache
|
.jython_cache
|
||||||
|
qywx.json
|
|
@ -6,9 +6,9 @@ ARG MS_VERSION=dev
|
||||||
|
|
||||||
RUN mkdir -p /opt/apps && mkdir -p /opt/jmeter
|
RUN mkdir -p /opt/apps && mkdir -p /opt/jmeter
|
||||||
|
|
||||||
ADD backend/target/backend-1.4.jar /opt/apps
|
COPY backend/target/backend-1.4.jar /opt/apps
|
||||||
|
|
||||||
ADD backend/target/classes/jmeter/ /opt/jmeter/
|
COPY backend/target/classes/jmeter/ /opt/jmeter/
|
||||||
|
|
||||||
ENV JAVA_APP_JAR=/opt/apps/backend-1.4.jar
|
ENV JAVA_APP_JAR=/opt/apps/backend-1.4.jar
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ MeterSphere is a one-stop open-source enterprise-class continuous testing platfo
|
||||||
- Performance Testing: Compatible with JMeter. Support Kubernetes and Cloud Environment. High concurrency, distributed performance testing with ease.
|
- Performance Testing: Compatible with JMeter. Support Kubernetes and Cloud Environment. High concurrency, distributed performance testing with ease.
|
||||||
- Team Collaboration: duo-levels tenants system, naturally support team co-op.
|
- Team Collaboration: duo-levels tenants system, naturally support team co-op.
|
||||||
|
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
Only need two steps to install MeterSphere:
|
Only need two steps to install MeterSphere:
|
||||||
|
@ -149,7 +148,6 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
## Technology stack
|
## Technology stack
|
||||||
|
|
||||||
- Backend: [Spring Boot](https://www.tutorialspoint.com/spring_boot/spring_boot_introduction.htm)
|
- Backend: [Spring Boot](https://www.tutorialspoint.com/spring_boot/spring_boot_introduction.htm)
|
||||||
|
@ -158,13 +156,12 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
|
||||||
- Basic infrastructure: [Docker](https://www.docker.com/), [Kubernetes](https://kubernetes.io/)
|
- Basic infrastructure: [Docker](https://www.docker.com/), [Kubernetes](https://kubernetes.io/)
|
||||||
- Test engine: [JMeter](https://jmeter.apache.org/)
|
- Test engine: [JMeter](https://jmeter.apache.org/)
|
||||||
|
|
||||||
|
|
||||||
## License & Copyright
|
## License & Copyright
|
||||||
|
|
||||||
Copyright (c) 2014-2020 飞致云 FIT2CLOUD, All rights reserved.
|
Copyright (c) 2014-2020 飞致云 FIT2CLOUD, All rights reserved.
|
||||||
|
|
||||||
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
https://www.gnu.org/licenses/gpl-2.0.html
|
<https://www.gnu.org/licenses/gpl-2.0.html>
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
25
README.md
25
README.md
|
@ -5,11 +5,11 @@
|
||||||
[![GitHub All Releases](https://img.shields.io/github/downloads/metersphere/metersphere/total)](https://github.com/metersphere/metersphere/releases)
|
[![GitHub All Releases](https://img.shields.io/github/downloads/metersphere/metersphere/total)](https://github.com/metersphere/metersphere/releases)
|
||||||
[![TesterHome](https://img.shields.io/badge/TTF-TesterHome-2955C5.svg)](https://testerhome.com/github_statistics)
|
[![TesterHome](https://img.shields.io/badge/TTF-TesterHome-2955C5.svg)](https://testerhome.com/github_statistics)
|
||||||
|
|
||||||
> [English](README_EN.md) | 中文
|
> [English](README-EN.md) | 中文
|
||||||
|
|
||||||
|Developer Wanted|
|
| Developer Wanted |
|
||||||
|----------------|
|
| ------------------------------------------------------------------------------------------------------------ |
|
||||||
|我们正在寻找开发者,欢迎加入我们共同打造更好用、更强大的 MeterSphere。联系我们: <metersphere@fit2cloud.com>|
|
| 我们正在寻找开发者,欢迎加入我们共同打造更好用、更强大的 MeterSphere。联系我们: [metersphere@fit2cloud.com](mailto:metersphere@fit2cloud.com) |
|
||||||
|
|
||||||
MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟踪、接口测试、性能测试、团队协作等功能,兼容JMeter 等开源标准,有效助力开发和测试团队充分利用云弹性进行高度可扩展的自动化测试,加速高质量软件的交付。
|
MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟踪、接口测试、性能测试、团队协作等功能,兼容JMeter 等开源标准,有效助力开发和测试团队充分利用云弹性进行高度可扩展的自动化测试,加速高质量软件的交付。
|
||||||
|
|
||||||
|
@ -20,16 +20,16 @@ MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟
|
||||||
|
|
||||||
![产品定位](https://metersphere.oss-cn-hangzhou.aliyuncs.com/img/ct-devops.png)
|
![产品定位](https://metersphere.oss-cn-hangzhou.aliyuncs.com/img/ct-devops.png)
|
||||||
|
|
||||||
|
|
||||||
> 如需进一步了解 MeterSphere 开源项目,推荐阅读 [MeterSphere 的初心和使命](https://mp.weixin.qq.com/s/DpCt3BNgBTlV3sJ5qtPmZw)
|
> 如需进一步了解 MeterSphere 开源项目,推荐阅读 [MeterSphere 的初心和使命](https://mp.weixin.qq.com/s/DpCt3BNgBTlV3sJ5qtPmZw)
|
||||||
|
|
||||||
## 在线体验
|
## 在线体验
|
||||||
- 环境地址:https://demo.metersphere.com/
|
|
||||||
|
- 环境地址:<https://demo.metersphere.com/>
|
||||||
- 用户名:demo
|
- 用户名:demo
|
||||||
- 密码:P@ssw0rd123..
|
- 密码:P@ssw0rd123..
|
||||||
|
|
||||||
| :warning: 注意 |
|
| :warning: 注意 |
|
||||||
|:---------------------------|
|
| :--------------------------- |
|
||||||
| 该环境仅作体验目的使用,我们会定时清理、重置数据! |
|
| 该环境仅作体验目的使用,我们会定时清理、重置数据! |
|
||||||
| 请勿修改体验环境用户的密码! |
|
| 请勿修改体验环境用户的密码! |
|
||||||
| 请勿在环境中添加业务生产环境地址、用户名密码等敏感信息! |
|
| 请勿在环境中添加业务生产环境地址、用户名密码等敏感信息! |
|
||||||
|
@ -38,8 +38,8 @@ MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟
|
||||||
|
|
||||||
仅需两步快速安装 MeterSphere:
|
仅需两步快速安装 MeterSphere:
|
||||||
|
|
||||||
1. 准备一台不小于 8 G内存的 64位 Linux 主机;
|
1. 准备一台不小于 8 G内存的 64位 Linux 主机;
|
||||||
2. 以 root 用户执行如下命令一键安装 MeterSphere。
|
2. 以 root 用户执行如下命令一键安装 MeterSphere。
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/quick_start.sh | sh
|
curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/quick_start.sh | sh
|
||||||
|
@ -51,7 +51,9 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
|
||||||
- [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4)
|
- [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4)
|
||||||
|
|
||||||
## MeterSphere 企业版
|
## MeterSphere 企业版
|
||||||
|
|
||||||
[申请企业版使用](https://jinshuju.net/f/CzzAOe)
|
[申请企业版使用](https://jinshuju.net/f/CzzAOe)
|
||||||
|
|
||||||
> 注: 企业版支持离线安装,申请通过后会提供高速下载链接
|
> 注: 企业版支持离线安装,申请通过后会提供高速下载链接
|
||||||
|
|
||||||
## 相关工具
|
## 相关工具
|
||||||
|
@ -63,10 +65,11 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
|
||||||
|
|
||||||
MeterSphere 版本号命名规则为:v大版本.功能版本.Bug修复版本。比如:
|
MeterSphere 版本号命名规则为:v大版本.功能版本.Bug修复版本。比如:
|
||||||
|
|
||||||
```
|
```text
|
||||||
v1.0.1 是 v1.0.0 之后的Bug修复版本;
|
v1.0.1 是 v1.0.0 之后的Bug修复版本;
|
||||||
v1.1.0 是 v1.0.0 之后的功能版本。
|
v1.1.0 是 v1.0.0 之后的功能版本。
|
||||||
```
|
```
|
||||||
|
|
||||||
像其它优秀开源项目一样,MeterSphere 将每月发布一个功能版本。
|
像其它优秀开源项目一样,MeterSphere 将每月发布一个功能版本。
|
||||||
|
|
||||||
## 技术优势
|
## 技术优势
|
||||||
|
@ -304,6 +307,6 @@ Copyright (c) 2014-2020 飞致云 FIT2CLOUD, All rights reserved.
|
||||||
|
|
||||||
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
https://www.gnu.org/licenses/gpl-2.0.html
|
<https://www.gnu.org/licenses/gpl-2.0.html>
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
## v1.1 (已发布)
|
## v1.1 (已发布)
|
||||||
|
|
||||||
- [x] 浏览器插件支持编辑录制后的内容
|
- [x] 浏览器插件支持编辑录制后的内容
|
||||||
- [x] 插件录制的脚本支持用作接口测试
|
- [x] 插件录制的脚本支持用作接口测试
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
- [ ] 优化性能测试压力配置模式
|
- [ ] 优化性能测试压力配置模式
|
||||||
|
|
||||||
## v1.3 (已发布)
|
## v1.3 (已发布)
|
||||||
|
|
||||||
- [x] 测试跟踪:用例评审机制
|
- [x] 测试跟踪:用例评审机制
|
||||||
- [x] 测试跟踪:测试计划关联用例支持跨项目
|
- [x] 测试跟踪:测试计划关联用例支持跨项目
|
||||||
- [ ] 测试跟踪:测试用例支持贴图
|
- [ ] 测试跟踪:测试用例支持贴图
|
||||||
|
@ -39,12 +40,14 @@
|
||||||
- [x] 其他:报告导出
|
- [x] 其他:报告导出
|
||||||
|
|
||||||
## v1.4 (已发布)
|
## v1.4 (已发布)
|
||||||
|
|
||||||
- [x] 测试跟踪模块编辑测试用例支持上传附件
|
- [x] 测试跟踪模块编辑测试用例支持上传附件
|
||||||
- [x] 支持上传并引用自定义Jar包
|
- [x] 支持上传并引用自定义Jar包
|
||||||
- [x] 接口测试支持TCP协议请求
|
- [x] 接口测试支持TCP协议请求
|
||||||
- [x] 全新的消息通知设置,支持企业微信、钉钉机器人通知
|
- [x] 全新的消息通知设置,支持企业微信、钉钉机器人通知
|
||||||
|
|
||||||
## v1.5 (开发中)
|
## v1.5 (开发中)
|
||||||
|
|
||||||
- [ ] 性能测试:优化并发数、持续时间等压力配置方式
|
- [ ] 性能测试:优化并发数、持续时间等压力配置方式
|
||||||
- [ ] 性能测试:支持使用了额外插件的 JMX 文件
|
- [ ] 性能测试:支持使用了额外插件的 JMX 文件
|
||||||
- [ ] 性能测试:自动修改 csv 等数据文件引用路径
|
- [ ] 性能测试:自动修改 csv 等数据文件引用路径
|
||||||
|
@ -53,6 +56,7 @@
|
||||||
- [ ] 其他:Jenkins 插件支持 pipeline 方式调用
|
- [ ] 其他:Jenkins 插件支持 pipeline 方式调用
|
||||||
|
|
||||||
## 规划中
|
## 规划中
|
||||||
|
|
||||||
- [ ] 接口测试支持添加 WebSocket 协议请求
|
- [ ] 接口测试支持添加 WebSocket 协议请求
|
||||||
- [ ] 接口管理功能
|
- [ ] 接口管理功能
|
||||||
- [ ] 集成云平台动态管理测试资源池
|
- [ ] 集成云平台动态管理测试资源池
|
||||||
|
|
|
@ -156,7 +156,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.python</groupId>
|
<groupId>org.python</groupId>
|
||||||
<artifactId>jython-standalone</artifactId>
|
<artifactId>jython-standalone</artifactId>
|
||||||
<version>2.7.0</version>
|
<version>2.7.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -22,5 +22,7 @@ public class LoadTestReport implements Serializable {
|
||||||
|
|
||||||
private String triggerMode;
|
private String triggerMode;
|
||||||
|
|
||||||
|
private String fileId;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
}
|
|
@ -643,6 +643,76 @@ public class LoadTestReportExample {
|
||||||
addCriterion("trigger_mode not between", value1, value2, "triggerMode");
|
addCriterion("trigger_mode not between", value1, value2, "triggerMode");
|
||||||
return (Criteria) this;
|
return (Criteria) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdIsNull() {
|
||||||
|
addCriterion("file_id is null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdIsNotNull() {
|
||||||
|
addCriterion("file_id is not null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdEqualTo(String value) {
|
||||||
|
addCriterion("file_id =", value, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdNotEqualTo(String value) {
|
||||||
|
addCriterion("file_id <>", value, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdGreaterThan(String value) {
|
||||||
|
addCriterion("file_id >", value, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdGreaterThanOrEqualTo(String value) {
|
||||||
|
addCriterion("file_id >=", value, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdLessThan(String value) {
|
||||||
|
addCriterion("file_id <", value, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdLessThanOrEqualTo(String value) {
|
||||||
|
addCriterion("file_id <=", value, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdLike(String value) {
|
||||||
|
addCriterion("file_id like", value, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdNotLike(String value) {
|
||||||
|
addCriterion("file_id not like", value, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdIn(List<String> values) {
|
||||||
|
addCriterion("file_id in", values, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdNotIn(List<String> values) {
|
||||||
|
addCriterion("file_id not in", values, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdBetween(String value1, String value2) {
|
||||||
|
addCriterion("file_id between", value1, value2, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andFileIdNotBetween(String value1, String value2) {
|
||||||
|
addCriterion("file_id not between", value1, value2, "fileId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Criteria extends GeneratedCriteria {
|
public static class Criteria extends GeneratedCriteria {
|
||||||
|
|
|
@ -21,5 +21,7 @@ public class Project implements Serializable {
|
||||||
|
|
||||||
private String jiraKey;
|
private String jiraKey;
|
||||||
|
|
||||||
|
private String zentaoId;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
}
|
|
@ -643,6 +643,76 @@ public class ProjectExample {
|
||||||
addCriterion("jira_key not between", value1, value2, "jiraKey");
|
addCriterion("jira_key not between", value1, value2, "jiraKey");
|
||||||
return (Criteria) this;
|
return (Criteria) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdIsNull() {
|
||||||
|
addCriterion("zentao_id is null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdIsNotNull() {
|
||||||
|
addCriterion("zentao_id is not null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdEqualTo(String value) {
|
||||||
|
addCriterion("zentao_id =", value, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdNotEqualTo(String value) {
|
||||||
|
addCriterion("zentao_id <>", value, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdGreaterThan(String value) {
|
||||||
|
addCriterion("zentao_id >", value, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdGreaterThanOrEqualTo(String value) {
|
||||||
|
addCriterion("zentao_id >=", value, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdLessThan(String value) {
|
||||||
|
addCriterion("zentao_id <", value, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdLessThanOrEqualTo(String value) {
|
||||||
|
addCriterion("zentao_id <=", value, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdLike(String value) {
|
||||||
|
addCriterion("zentao_id like", value, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdNotLike(String value) {
|
||||||
|
addCriterion("zentao_id not like", value, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdIn(List<String> values) {
|
||||||
|
addCriterion("zentao_id in", values, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdNotIn(List<String> values) {
|
||||||
|
addCriterion("zentao_id not in", values, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdBetween(String value1, String value2) {
|
||||||
|
addCriterion("zentao_id between", value1, value2, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andZentaoIdNotBetween(String value1, String value2) {
|
||||||
|
addCriterion("zentao_id not between", value1, value2, "zentaoId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Criteria extends GeneratedCriteria {
|
public static class Criteria extends GeneratedCriteria {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<result column="status" jdbcType="VARCHAR" property="status" />
|
<result column="status" jdbcType="VARCHAR" property="status" />
|
||||||
<result column="user_id" jdbcType="VARCHAR" property="userId" />
|
<result column="user_id" jdbcType="VARCHAR" property="userId" />
|
||||||
<result column="trigger_mode" jdbcType="VARCHAR" property="triggerMode" />
|
<result column="trigger_mode" jdbcType="VARCHAR" property="triggerMode" />
|
||||||
|
<result column="file_id" jdbcType="VARCHAR" property="fileId" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.LoadTestReportWithBLOBs">
|
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.LoadTestReportWithBLOBs">
|
||||||
<result column="description" jdbcType="LONGVARCHAR" property="description" />
|
<result column="description" jdbcType="LONGVARCHAR" property="description" />
|
||||||
|
@ -74,7 +75,7 @@
|
||||||
</where>
|
</where>
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, test_id, `name`, create_time, update_time, `status`, user_id, trigger_mode
|
id, test_id, `name`, create_time, update_time, `status`, user_id, trigger_mode, file_id
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="Blob_Column_List">
|
<sql id="Blob_Column_List">
|
||||||
description, load_configuration
|
description, load_configuration
|
||||||
|
@ -130,12 +131,12 @@
|
||||||
<insert id="insert" parameterType="io.metersphere.base.domain.LoadTestReportWithBLOBs">
|
<insert id="insert" parameterType="io.metersphere.base.domain.LoadTestReportWithBLOBs">
|
||||||
INSERT INTO load_test_report (id, test_id, `name`,
|
INSERT INTO load_test_report (id, test_id, `name`,
|
||||||
create_time, update_time, `status`,
|
create_time, update_time, `status`,
|
||||||
user_id, trigger_mode, description,
|
user_id, trigger_mode, file_id,
|
||||||
load_configuration)
|
description, load_configuration)
|
||||||
VALUES (#{id,jdbcType=VARCHAR}, #{testId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
VALUES (#{id,jdbcType=VARCHAR}, #{testId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
||||||
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{status,jdbcType=VARCHAR},
|
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{status,jdbcType=VARCHAR},
|
||||||
#{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR},
|
#{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR},
|
||||||
#{loadConfiguration,jdbcType=LONGVARCHAR})
|
#{description,jdbcType=LONGVARCHAR}, #{loadConfiguration,jdbcType=LONGVARCHAR})
|
||||||
</insert>
|
</insert>
|
||||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.LoadTestReportWithBLOBs">
|
<insert id="insertSelective" parameterType="io.metersphere.base.domain.LoadTestReportWithBLOBs">
|
||||||
insert into load_test_report
|
insert into load_test_report
|
||||||
|
@ -164,6 +165,9 @@
|
||||||
<if test="triggerMode != null">
|
<if test="triggerMode != null">
|
||||||
trigger_mode,
|
trigger_mode,
|
||||||
</if>
|
</if>
|
||||||
|
<if test="fileId != null">
|
||||||
|
file_id,
|
||||||
|
</if>
|
||||||
<if test="description != null">
|
<if test="description != null">
|
||||||
description,
|
description,
|
||||||
</if>
|
</if>
|
||||||
|
@ -196,6 +200,9 @@
|
||||||
<if test="triggerMode != null">
|
<if test="triggerMode != null">
|
||||||
#{triggerMode,jdbcType=VARCHAR},
|
#{triggerMode,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="fileId != null">
|
||||||
|
#{fileId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
<if test="description != null">
|
<if test="description != null">
|
||||||
#{description,jdbcType=LONGVARCHAR},
|
#{description,jdbcType=LONGVARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
@ -237,6 +244,9 @@
|
||||||
<if test="record.triggerMode != null">
|
<if test="record.triggerMode != null">
|
||||||
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
|
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="record.fileId != null">
|
||||||
|
file_id = #{record.fileId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
<if test="record.description != null">
|
<if test="record.description != null">
|
||||||
description = #{record.description,jdbcType=LONGVARCHAR},
|
description = #{record.description,jdbcType=LONGVARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
@ -258,6 +268,7 @@
|
||||||
`status` = #{record.status,jdbcType=VARCHAR},
|
`status` = #{record.status,jdbcType=VARCHAR},
|
||||||
user_id = #{record.userId,jdbcType=VARCHAR},
|
user_id = #{record.userId,jdbcType=VARCHAR},
|
||||||
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
|
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
|
||||||
|
file_id = #{record.fileId,jdbcType=VARCHAR},
|
||||||
description = #{record.description,jdbcType=LONGVARCHAR},
|
description = #{record.description,jdbcType=LONGVARCHAR},
|
||||||
load_configuration = #{record.loadConfiguration,jdbcType=LONGVARCHAR}
|
load_configuration = #{record.loadConfiguration,jdbcType=LONGVARCHAR}
|
||||||
<if test="_parameter != null">
|
<if test="_parameter != null">
|
||||||
|
@ -273,7 +284,8 @@
|
||||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||||
`status` = #{record.status,jdbcType=VARCHAR},
|
`status` = #{record.status,jdbcType=VARCHAR},
|
||||||
user_id = #{record.userId,jdbcType=VARCHAR},
|
user_id = #{record.userId,jdbcType=VARCHAR},
|
||||||
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR}
|
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
|
||||||
|
file_id = #{record.fileId,jdbcType=VARCHAR}
|
||||||
<if test="_parameter != null">
|
<if test="_parameter != null">
|
||||||
<include refid="Update_By_Example_Where_Clause" />
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
</if>
|
</if>
|
||||||
|
@ -302,6 +314,9 @@
|
||||||
<if test="triggerMode != null">
|
<if test="triggerMode != null">
|
||||||
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
|
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="fileId != null">
|
||||||
|
file_id = #{fileId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
<if test="description != null">
|
<if test="description != null">
|
||||||
description = #{description,jdbcType=LONGVARCHAR},
|
description = #{description,jdbcType=LONGVARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
@ -312,27 +327,29 @@
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
where id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.LoadTestReportWithBLOBs">
|
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.LoadTestReportWithBLOBs">
|
||||||
update load_test_report
|
UPDATE load_test_report
|
||||||
set test_id = #{testId,jdbcType=VARCHAR},
|
SET test_id = #{testId,jdbcType=VARCHAR},
|
||||||
`name` = #{name,jdbcType=VARCHAR},
|
`name` = #{name,jdbcType=VARCHAR},
|
||||||
create_time = #{createTime,jdbcType=BIGINT},
|
create_time = #{createTime,jdbcType=BIGINT},
|
||||||
update_time = #{updateTime,jdbcType=BIGINT},
|
update_time = #{updateTime,jdbcType=BIGINT},
|
||||||
`status` = #{status,jdbcType=VARCHAR},
|
`status` = #{status,jdbcType=VARCHAR},
|
||||||
user_id = #{userId,jdbcType=VARCHAR},
|
user_id = #{userId,jdbcType=VARCHAR},
|
||||||
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
|
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
|
||||||
|
file_id = #{fileId,jdbcType=VARCHAR},
|
||||||
description = #{description,jdbcType=LONGVARCHAR},
|
description = #{description,jdbcType=LONGVARCHAR},
|
||||||
load_configuration = #{loadConfiguration,jdbcType=LONGVARCHAR}
|
load_configuration = #{loadConfiguration,jdbcType=LONGVARCHAR}
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
WHERE id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.LoadTestReport">
|
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.LoadTestReport">
|
||||||
update load_test_report
|
UPDATE load_test_report
|
||||||
set test_id = #{testId,jdbcType=VARCHAR},
|
SET test_id = #{testId,jdbcType=VARCHAR},
|
||||||
`name` = #{name,jdbcType=VARCHAR},
|
`name` = #{name,jdbcType=VARCHAR},
|
||||||
create_time = #{createTime,jdbcType=BIGINT},
|
create_time = #{createTime,jdbcType=BIGINT},
|
||||||
update_time = #{updateTime,jdbcType=BIGINT},
|
update_time = #{updateTime,jdbcType=BIGINT},
|
||||||
`status` = #{status,jdbcType=VARCHAR},
|
`status` = #{status,jdbcType=VARCHAR},
|
||||||
user_id = #{userId,jdbcType=VARCHAR},
|
user_id = #{userId,jdbcType=VARCHAR},
|
||||||
trigger_mode = #{triggerMode,jdbcType=VARCHAR}
|
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
file_id = #{fileId,jdbcType=VARCHAR}
|
||||||
|
WHERE id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
</mapper>
|
</mapper>
|
|
@ -10,6 +10,7 @@
|
||||||
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
|
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
|
||||||
<result column="tapd_id" jdbcType="VARCHAR" property="tapdId" />
|
<result column="tapd_id" jdbcType="VARCHAR" property="tapdId" />
|
||||||
<result column="jira_key" jdbcType="VARCHAR" property="jiraKey" />
|
<result column="jira_key" jdbcType="VARCHAR" property="jiraKey" />
|
||||||
|
<result column="zentao_id" jdbcType="VARCHAR" property="zentaoId" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<sql id="Example_Where_Clause">
|
<sql id="Example_Where_Clause">
|
||||||
<where>
|
<where>
|
||||||
|
@ -70,7 +71,8 @@
|
||||||
</where>
|
</where>
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key
|
id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key,
|
||||||
|
zentao_id
|
||||||
</sql>
|
</sql>
|
||||||
<select id="selectByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultMap="BaseResultMap">
|
<select id="selectByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultMap="BaseResultMap">
|
||||||
select
|
select
|
||||||
|
@ -105,10 +107,12 @@
|
||||||
<insert id="insert" parameterType="io.metersphere.base.domain.Project">
|
<insert id="insert" parameterType="io.metersphere.base.domain.Project">
|
||||||
insert into project (id, workspace_id, `name`,
|
insert into project (id, workspace_id, `name`,
|
||||||
description, create_time, update_time,
|
description, create_time, update_time,
|
||||||
tapd_id, jira_key)
|
tapd_id, jira_key, zentao_id
|
||||||
|
)
|
||||||
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
||||||
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
|
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
|
||||||
#{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR})
|
#{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR}, #{zentaoId,jdbcType=VARCHAR}
|
||||||
|
)
|
||||||
</insert>
|
</insert>
|
||||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.Project">
|
<insert id="insertSelective" parameterType="io.metersphere.base.domain.Project">
|
||||||
insert into project
|
insert into project
|
||||||
|
@ -137,6 +141,9 @@
|
||||||
<if test="jiraKey != null">
|
<if test="jiraKey != null">
|
||||||
jira_key,
|
jira_key,
|
||||||
</if>
|
</if>
|
||||||
|
<if test="zentaoId != null">
|
||||||
|
zentao_id,
|
||||||
|
</if>
|
||||||
</trim>
|
</trim>
|
||||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
<if test="id != null">
|
<if test="id != null">
|
||||||
|
@ -163,6 +170,9 @@
|
||||||
<if test="jiraKey != null">
|
<if test="jiraKey != null">
|
||||||
#{jiraKey,jdbcType=VARCHAR},
|
#{jiraKey,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="zentaoId != null">
|
||||||
|
#{zentaoId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
</trim>
|
</trim>
|
||||||
</insert>
|
</insert>
|
||||||
<select id="countByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultType="java.lang.Long">
|
<select id="countByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultType="java.lang.Long">
|
||||||
|
@ -198,6 +208,9 @@
|
||||||
<if test="record.jiraKey != null">
|
<if test="record.jiraKey != null">
|
||||||
jira_key = #{record.jiraKey,jdbcType=VARCHAR},
|
jira_key = #{record.jiraKey,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="record.zentaoId != null">
|
||||||
|
zentao_id = #{record.zentaoId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
</set>
|
</set>
|
||||||
<if test="_parameter != null">
|
<if test="_parameter != null">
|
||||||
<include refid="Update_By_Example_Where_Clause" />
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
|
@ -212,7 +225,8 @@
|
||||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||||
tapd_id = #{record.tapdId,jdbcType=VARCHAR},
|
tapd_id = #{record.tapdId,jdbcType=VARCHAR},
|
||||||
jira_key = #{record.jiraKey,jdbcType=VARCHAR}
|
jira_key = #{record.jiraKey,jdbcType=VARCHAR},
|
||||||
|
zentao_id = #{record.zentaoId,jdbcType=VARCHAR}
|
||||||
<if test="_parameter != null">
|
<if test="_parameter != null">
|
||||||
<include refid="Update_By_Example_Where_Clause" />
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
</if>
|
</if>
|
||||||
|
@ -241,6 +255,9 @@
|
||||||
<if test="jiraKey != null">
|
<if test="jiraKey != null">
|
||||||
jira_key = #{jiraKey,jdbcType=VARCHAR},
|
jira_key = #{jiraKey,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="zentaoId != null">
|
||||||
|
zentao_id = #{zentaoId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
</set>
|
</set>
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
where id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
|
@ -252,7 +269,8 @@
|
||||||
create_time = #{createTime,jdbcType=BIGINT},
|
create_time = #{createTime,jdbcType=BIGINT},
|
||||||
update_time = #{updateTime,jdbcType=BIGINT},
|
update_time = #{updateTime,jdbcType=BIGINT},
|
||||||
tapd_id = #{tapdId,jdbcType=VARCHAR},
|
tapd_id = #{tapdId,jdbcType=VARCHAR},
|
||||||
jira_key = #{jiraKey,jdbcType=VARCHAR}
|
jira_key = #{jiraKey,jdbcType=VARCHAR},
|
||||||
|
zentao_id = #{zentaoId,jdbcType=VARCHAR}
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
where id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
</mapper>
|
</mapper>
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<select id="getProjectWithWorkspace" resultType="io.metersphere.dto.ProjectDTO">
|
<select id="getProjectWithWorkspace" resultType="io.metersphere.dto.ProjectDTO">
|
||||||
select p.id, p.workspace_id, p.name, p.description, p.update_time,
|
select p.id, p.workspace_id, p.name, p.description, p.update_time,
|
||||||
p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key
|
p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key, p.zentao_id
|
||||||
from project p
|
from project p
|
||||||
join workspace w on p.workspace_id = w.id
|
join workspace w on p.workspace_id = w.id
|
||||||
<where>
|
<where>
|
||||||
|
@ -37,6 +37,9 @@
|
||||||
<if test="platform == 'Tapd'">
|
<if test="platform == 'Tapd'">
|
||||||
tapd_id = null
|
tapd_id = null
|
||||||
</if>
|
</if>
|
||||||
|
<if test="platform == 'Zentao'">
|
||||||
|
zentao_id = null
|
||||||
|
</if>
|
||||||
</set>
|
</set>
|
||||||
where project.id in (select id from (select id
|
where project.id in (select id from (select id
|
||||||
from project
|
from project
|
||||||
|
|
|
@ -49,8 +49,16 @@
|
||||||
|
|
||||||
<select id="getOrgMemberList" resultType="io.metersphere.base.domain.User">
|
<select id="getOrgMemberList" resultType="io.metersphere.base.domain.User">
|
||||||
SELECT DISTINCT * FROM (
|
SELECT DISTINCT * FROM (
|
||||||
SELECT `user`.* FROM user_role JOIN `user` ON user_role.user_id = `user`.id
|
SELECT `user`.*
|
||||||
WHERE user_role.source_id = #{orgMember.organizationId}
|
FROM user_role JOIN `user`
|
||||||
|
ON user_role.user_id = `user`.id
|
||||||
|
WHERE user_role.source_id in
|
||||||
|
(
|
||||||
|
SELECT id FROM workspace w
|
||||||
|
WHERE w.organization_id = #{orgMember.organizationId}
|
||||||
|
UNION
|
||||||
|
SELECT #{orgMember.organizationId} AS id FROM dual
|
||||||
|
)
|
||||||
<if test="orgMember.name != null">
|
<if test="orgMember.name != null">
|
||||||
AND `user`.name like CONCAT('%', #{orgMember.name},'%')
|
AND `user`.name like CONCAT('%', #{orgMember.name},'%')
|
||||||
</if>
|
</if>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
package io.metersphere.commons.constants;
|
package io.metersphere.commons.constants;
|
||||||
|
|
||||||
public enum IssuesManagePlatform {
|
public enum IssuesManagePlatform {
|
||||||
Tapd, Jira, Local
|
Tapd, Jira, Local, Zentao
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package io.metersphere.commons.constants;
|
||||||
public class RoleConstants {
|
public class RoleConstants {
|
||||||
public final static String ADMIN = "admin";
|
public final static String ADMIN = "admin";
|
||||||
public final static String ORG_ADMIN = "org_admin";
|
public final static String ORG_ADMIN = "org_admin";
|
||||||
|
public final static String ORG_MEMBER = "org_member";
|
||||||
public final static String TEST_VIEWER = "test_viewer";
|
public final static String TEST_VIEWER = "test_viewer";
|
||||||
public final static String TEST_MANAGER = "test_manager";
|
public final static String TEST_MANAGER = "test_manager";
|
||||||
public final static String TEST_USER = "test_user";
|
public final static String TEST_USER = "test_user";
|
||||||
|
|
|
@ -16,5 +16,5 @@ public class ProjectDTO {
|
||||||
private Long updateTime;
|
private Long updateTime;
|
||||||
private String tapdId;
|
private String tapdId;
|
||||||
private String jiraKey;
|
private String jiraKey;
|
||||||
|
private String zentaoId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.commons.collections4.MapUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.RegExUtils;
|
import org.apache.commons.lang3.RegExUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.mail.MailException;
|
||||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -99,10 +100,10 @@ public class MailService {
|
||||||
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
|
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
|
||||||
helper.setFrom(javaMailSender.getUsername());
|
helper.setFrom(javaMailSender.getUsername());
|
||||||
if (StringUtils.equals(type, NoticeConstants.API)) {
|
if (StringUtils.equals(type, NoticeConstants.API)) {
|
||||||
helper.setSubject("MeterSphere平台" + Translator.get("task_notification"));
|
helper.setSubject("MeterSphere平台" + Translator.get("task_notification_jenkins"));
|
||||||
}
|
}
|
||||||
if (StringUtils.equals(type, NoticeConstants.SCHEDULE)) {
|
if (StringUtils.equals(type, NoticeConstants.SCHEDULE)) {
|
||||||
helper.setSubject("MeterSphere平台" + Translator.get("task_notification_"));
|
helper.setSubject("MeterSphere平台" + Translator.get("task_notification"));
|
||||||
}
|
}
|
||||||
String[] users;
|
String[] users;
|
||||||
List<String> emails = new ArrayList<>();
|
List<String> emails = new ArrayList<>();
|
||||||
|
@ -113,7 +114,11 @@ public class MailService {
|
||||||
users = emails.toArray(new String[0]);
|
users = emails.toArray(new String[0]);
|
||||||
helper.setText(getContent(Template, context), true);
|
helper.setText(getContent(Template, context), true);
|
||||||
helper.setTo(users);
|
helper.setTo(users);
|
||||||
|
try {
|
||||||
javaMailSender.send(mimeMessage);
|
javaMailSender.send(mimeMessage);
|
||||||
|
} catch (MailException e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//测试评审
|
//测试评审
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@ import io.metersphere.performance.controller.request.ReportRequest;
|
||||||
import io.metersphere.performance.service.ReportService;
|
import io.metersphere.performance.service.ReportService;
|
||||||
import org.apache.shiro.authz.annotation.Logical;
|
import org.apache.shiro.authz.annotation.Logical;
|
||||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
@ -130,4 +133,13 @@ public class PerformanceReportController {
|
||||||
public void deleteReportBatch(@RequestBody DeleteReportRequest reportRequest) {
|
public void deleteReportBatch(@RequestBody DeleteReportRequest reportRequest) {
|
||||||
reportService.deleteReportBatch(reportRequest);
|
reportService.deleteReportBatch(reportRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/jtl/download/{reportId}")
|
||||||
|
public ResponseEntity<byte[]> downloadJtl(@PathVariable String reportId) {
|
||||||
|
byte[] bytes = reportService.downloadJtl(reportId);
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + reportId + ".jtl\"")
|
||||||
|
.body(bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,34 +39,36 @@ public class PerformanceNoticeTask {
|
||||||
private LoadTestReportMapper loadTestReportMapper;
|
private LoadTestReportMapper loadTestReportMapper;
|
||||||
|
|
||||||
private final ExecutorService executorService = Executors.newFixedThreadPool(20);
|
private final ExecutorService executorService = Executors.newFixedThreadPool(20);
|
||||||
private boolean isRunning = true;
|
|
||||||
|
|
||||||
@PreDestroy
|
private boolean isRunning=false;
|
||||||
|
|
||||||
|
/*@PreDestroy
|
||||||
public void preDestroy() {
|
public void preDestroy() {
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
public void registerNoticeTask(LoadTestReportWithBLOBs loadTestReport) {
|
public void registerNoticeTask(LoadTestReportWithBLOBs loadTestReport) {
|
||||||
int count = 20;
|
isRunning=true;
|
||||||
while (count-- > 0) {
|
executorService.submit(() -> {
|
||||||
|
LogUtil.info("性能测试定时任务");
|
||||||
|
while (isRunning) {
|
||||||
LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReport.getId());
|
LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReport.getId());
|
||||||
if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Completed.name())) {
|
if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Completed.name())) {
|
||||||
isRunning = false;
|
|
||||||
sendSuccessNotice(loadTestReportFromDatabase);
|
sendSuccessNotice(loadTestReportFromDatabase);
|
||||||
return;
|
isRunning=false;
|
||||||
}
|
}
|
||||||
if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Error.name())) {
|
if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Error.name())) {
|
||||||
isRunning = false;
|
|
||||||
sendFailNotice(loadTestReportFromDatabase);
|
sendFailNotice(loadTestReportFromDatabase);
|
||||||
return;
|
isRunning=false;
|
||||||
}
|
}
|
||||||
count--;
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000 * 4L);// 每分钟检查 loadtest 的状态
|
//查询定时任务是否关闭
|
||||||
|
Thread.sleep(1000 * 30);// 每分钟检查 loadtest 的状态
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LogUtil.error(e);
|
LogUtil.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendSuccessNotice(LoadTestReportWithBLOBs loadTestReport) {
|
public void sendSuccessNotice(LoadTestReportWithBLOBs loadTestReport) {
|
||||||
|
|
|
@ -785,7 +785,9 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
threadGroup.appendChild(createStringProp(document, "LogFilename", ""));
|
threadGroup.appendChild(createStringProp(document, "LogFilename", ""));
|
||||||
// bzm - Concurrency Thread Group "Thread Iterations Limit:" 设置为空
|
// bzm - Concurrency Thread Group "Thread Iterations Limit:" 设置为空
|
||||||
// threadGroup.appendChild(createStringProp(document, "Iterations", "1"));
|
// threadGroup.appendChild(createStringProp(document, "Iterations", "1"));
|
||||||
threadGroup.appendChild(createStringProp(document, "Unit", "M"));
|
// threadGroup.appendChild(createStringProp(document, "Unit", "M"));
|
||||||
|
// 单位改成秒
|
||||||
|
threadGroup.appendChild(createStringProp(document, "Unit", "S"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processCheckoutTimer(Element element) {
|
private void processCheckoutTimer(Element element) {
|
||||||
|
@ -878,6 +880,24 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processVariableThroughputTimer(Element variableThroughputTimer) {
|
private void processVariableThroughputTimer(Element variableThroughputTimer) {
|
||||||
|
Object durations = context.getProperty("duration");
|
||||||
|
Integer duration;
|
||||||
|
if (durations instanceof List) {
|
||||||
|
Object o = ((List<?>) durations).get(0);
|
||||||
|
duration = (Integer) o;
|
||||||
|
((List<?>) durations).remove(0);
|
||||||
|
} else {
|
||||||
|
duration = (Integer) durations;
|
||||||
|
}
|
||||||
|
Object rpsLimits = context.getProperty("rpsLimit");
|
||||||
|
String rpsLimit;
|
||||||
|
if (rpsLimits instanceof List) {
|
||||||
|
Object o = ((List<?>) rpsLimits).get(0);
|
||||||
|
((List<?>) rpsLimits).remove(0);
|
||||||
|
rpsLimit = o.toString();
|
||||||
|
} else {
|
||||||
|
rpsLimit = rpsLimits.toString();
|
||||||
|
}
|
||||||
if (variableThroughputTimer.getChildNodes().getLength() > 0) {
|
if (variableThroughputTimer.getChildNodes().getLength() > 0) {
|
||||||
final NodeList childNodes = variableThroughputTimer.getChildNodes();
|
final NodeList childNodes = variableThroughputTimer.getChildNodes();
|
||||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
|
@ -903,27 +923,9 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
stringPropCount++;
|
stringPropCount++;
|
||||||
} else {
|
} else {
|
||||||
stringPropCount = 0;
|
stringPropCount = 0;
|
||||||
Object durations = context.getProperty("duration");// 传入的是分钟数, 需要转化成秒数
|
prop.getFirstChild().setNodeValue(String.valueOf(duration));
|
||||||
Integer duration;
|
|
||||||
if (durations instanceof List) {
|
|
||||||
Object o = ((List<?>) durations).get(0);
|
|
||||||
duration = (Integer) o;
|
|
||||||
((List<?>) durations).remove(0);
|
|
||||||
} else {
|
|
||||||
duration = (Integer) durations;
|
|
||||||
}
|
|
||||||
prop.getFirstChild().setNodeValue(String.valueOf(duration * 60));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Object rpsLimits = context.getProperty("rpsLimit");
|
|
||||||
String rpsLimit;
|
|
||||||
if (rpsLimits instanceof List) {
|
|
||||||
Object o = ((List<?>) rpsLimits).get(0);
|
|
||||||
((List<?>) rpsLimits).remove(0);
|
|
||||||
rpsLimit = o.toString();
|
|
||||||
} else {
|
|
||||||
rpsLimit = rpsLimits.toString();
|
|
||||||
}
|
|
||||||
prop.getFirstChild().setNodeValue(rpsLimit);
|
prop.getFirstChild().setNodeValue(rpsLimit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,6 +207,7 @@ public class PerformanceTestService {
|
||||||
|
|
||||||
@Transactional(noRollbackFor = MSException.class)// 保存失败的信息
|
@Transactional(noRollbackFor = MSException.class)// 保存失败的信息
|
||||||
public String run(RunTestPlanRequest request) {
|
public String run(RunTestPlanRequest request) {
|
||||||
|
LogUtil.info("性能测试run测试");
|
||||||
final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId());
|
final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId());
|
||||||
if (request.getUserId() != null) {
|
if (request.getUserId() != null) {
|
||||||
loadTest.setUserId(request.getUserId());
|
loadTest.setUserId(request.getUserId());
|
||||||
|
|
|
@ -13,11 +13,13 @@ import io.metersphere.commons.utils.ServiceUtils;
|
||||||
import io.metersphere.controller.request.OrderRequest;
|
import io.metersphere.controller.request.OrderRequest;
|
||||||
import io.metersphere.dto.LogDetailDTO;
|
import io.metersphere.dto.LogDetailDTO;
|
||||||
import io.metersphere.dto.ReportDTO;
|
import io.metersphere.dto.ReportDTO;
|
||||||
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.performance.base.*;
|
import io.metersphere.performance.base.*;
|
||||||
import io.metersphere.performance.controller.request.DeleteReportRequest;
|
import io.metersphere.performance.controller.request.DeleteReportRequest;
|
||||||
import io.metersphere.performance.controller.request.ReportRequest;
|
import io.metersphere.performance.controller.request.ReportRequest;
|
||||||
import io.metersphere.performance.engine.Engine;
|
import io.metersphere.performance.engine.Engine;
|
||||||
import io.metersphere.performance.engine.EngineFactory;
|
import io.metersphere.performance.engine.EngineFactory;
|
||||||
|
import io.metersphere.service.FileService;
|
||||||
import io.metersphere.service.TestResourceService;
|
import io.metersphere.service.TestResourceService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -47,6 +49,8 @@ public class ReportService {
|
||||||
private TestResourceService testResourceService;
|
private TestResourceService testResourceService;
|
||||||
@Resource
|
@Resource
|
||||||
private LoadTestReportDetailMapper loadTestReportDetailMapper;
|
private LoadTestReportDetailMapper loadTestReportDetailMapper;
|
||||||
|
@Resource
|
||||||
|
private FileService fileService;
|
||||||
|
|
||||||
public List<ReportDTO> getRecentReportList(ReportRequest request) {
|
public List<ReportDTO> getRecentReportList(ReportRequest request) {
|
||||||
List<OrderRequest> orders = new ArrayList<>();
|
List<OrderRequest> orders = new ArrayList<>();
|
||||||
|
@ -168,7 +172,10 @@ public class ReportService {
|
||||||
|
|
||||||
public void checkReportStatus(String reportId) {
|
public void checkReportStatus(String reportId) {
|
||||||
LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
|
LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||||
String reportStatus = loadTestReport.getStatus();
|
String reportStatus = "";
|
||||||
|
if (loadTestReport != null) {
|
||||||
|
reportStatus = loadTestReport.getStatus();
|
||||||
|
}
|
||||||
if (StringUtils.equals(PerformanceTestStatus.Error.name(), reportStatus)) {
|
if (StringUtils.equals(PerformanceTestStatus.Error.name(), reportStatus)) {
|
||||||
MSException.throwException("Report generation error!");
|
MSException.throwException("Report generation error!");
|
||||||
}
|
}
|
||||||
|
@ -268,4 +275,12 @@ public class ReportService {
|
||||||
String content = getContent(id, ReportKeys.ResponseCodeChart);
|
String content = getContent(id, ReportKeys.ResponseCodeChart);
|
||||||
return JSON.parseArray(content, ChartsData.class);
|
return JSON.parseArray(content, ChartsData.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] downloadJtl(String reportId) {
|
||||||
|
LoadTestReportWithBLOBs report = getReport(reportId);
|
||||||
|
if (StringUtils.isBlank(report.getFileId())) {
|
||||||
|
throw new RuntimeException(Translator.get("load_test_report_file_not_exist"));
|
||||||
|
}
|
||||||
|
return fileService.loadFileAsBytes(report.getFileId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,12 +171,11 @@ public class OrganizationService {
|
||||||
SessionUser sessionUser = SessionUtils.getUser();
|
SessionUser sessionUser = SessionUtils.getUser();
|
||||||
UserDTO user = userService.getUserDTO(sessionUser.getId());
|
UserDTO user = userService.getUserDTO(sessionUser.getId());
|
||||||
List<String> collect = user.getUserRoles().stream()
|
List<String> collect = user.getUserRoles().stream()
|
||||||
.filter(ur -> RoleConstants.ORG_ADMIN.equals(ur.getRoleId()))
|
.filter(ur -> RoleConstants.ORG_ADMIN.equals(ur.getRoleId()) || RoleConstants.ORG_MEMBER.equals(ur.getRoleId()))
|
||||||
.map(UserRole::getSourceId)
|
.map(UserRole::getSourceId)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
if (!collect.contains(organizationId)) {
|
if (!collect.contains(organizationId)) {
|
||||||
MSException.throwException(Translator.get("organization_does_not_belong_to_user"));
|
MSException.throwException(Translator.get("organization_does_not_belong_to_user"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.track.controller;
|
||||||
|
|
||||||
import io.metersphere.base.domain.Issues;
|
import io.metersphere.base.domain.Issues;
|
||||||
import io.metersphere.track.issue.PlatformUser;
|
import io.metersphere.track.issue.PlatformUser;
|
||||||
|
import io.metersphere.track.issue.ZentaoBuild;
|
||||||
import io.metersphere.track.service.IssuesService;
|
import io.metersphere.track.service.IssuesService;
|
||||||
import io.metersphere.track.request.testcase.IssuesRequest;
|
import io.metersphere.track.request.testcase.IssuesRequest;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@ -42,8 +43,19 @@ public class TestCaseIssuesController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/tapd/user/{caseId}")
|
@GetMapping("/tapd/user/{caseId}")
|
||||||
public List<PlatformUser> getPlatformUsers(@PathVariable String caseId) {
|
public List<PlatformUser> getTapdUsers(@PathVariable String caseId) {
|
||||||
return issuesService.getTapdProjectUsers(caseId);
|
return issuesService.getTapdProjectUsers(caseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/zentao/user/{caseId}")
|
||||||
|
public List<PlatformUser> getZentaoUsers(@PathVariable String caseId) {
|
||||||
|
return issuesService.getZentaoUsers(caseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/zentao/builds/{caseId}")
|
||||||
|
public List<ZentaoBuild> getZentaoBuilds(@PathVariable String caseId) {
|
||||||
|
return issuesService.getZentaoBuilds(caseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,13 @@ import java.util.List;
|
||||||
public class IssueFactory {
|
public class IssueFactory {
|
||||||
public static AbstractIssuePlatform createPlatform(String platform, IssuesRequest addIssueRequest) {
|
public static AbstractIssuePlatform createPlatform(String platform, IssuesRequest addIssueRequest) {
|
||||||
if (StringUtils.equals(IssuesManagePlatform.Tapd.toString(), platform)) {
|
if (StringUtils.equals(IssuesManagePlatform.Tapd.toString(), platform)) {
|
||||||
return new TapdIssue(addIssueRequest);
|
return new TapdPlatform(addIssueRequest);
|
||||||
} else if (StringUtils.equals(IssuesManagePlatform.Jira.toString(), platform)) {
|
} else if (StringUtils.equals(IssuesManagePlatform.Jira.toString(), platform)) {
|
||||||
return new JiraIssue(addIssueRequest);
|
return new JiraPlatform(addIssueRequest);
|
||||||
|
} else if (StringUtils.equals(IssuesManagePlatform.Zentao.toString(), platform)) {
|
||||||
|
return new ZentaoPlatform(addIssueRequest);
|
||||||
} else if (StringUtils.equals("LOCAL", platform)) {
|
} else if (StringUtils.equals("LOCAL", platform)) {
|
||||||
return new LocalIssue(addIssueRequest);
|
return new LocalPlatform(addIssueRequest);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,10 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class JiraIssue extends AbstractIssuePlatform {
|
public class JiraPlatform extends AbstractIssuePlatform {
|
||||||
|
|
||||||
|
|
||||||
public JiraIssue(IssuesRequest issuesRequest) {
|
public JiraPlatform(IssuesRequest issuesRequest) {
|
||||||
super(issuesRequest);
|
super(issuesRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ import io.metersphere.track.request.testcase.IssuesRequest;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class LocalIssue extends AbstractIssuePlatform {
|
public class LocalPlatform extends AbstractIssuePlatform {
|
||||||
|
|
||||||
public LocalIssue(IssuesRequest issuesRequest) {
|
public LocalPlatform(IssuesRequest issuesRequest) {
|
||||||
super(issuesRequest);
|
super(issuesRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,10 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class TapdIssue extends AbstractIssuePlatform {
|
public class TapdPlatform extends AbstractIssuePlatform {
|
||||||
|
|
||||||
|
|
||||||
public TapdIssue(IssuesRequest issueRequest) {
|
public TapdPlatform(IssuesRequest issueRequest) {
|
||||||
super(issueRequest);
|
super(issueRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package io.metersphere.track.issue;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ZentaoBuild {
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
}
|
|
@ -0,0 +1,300 @@
|
||||||
|
package io.metersphere.track.issue;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import io.metersphere.base.domain.*;
|
||||||
|
import io.metersphere.commons.constants.IssuesManagePlatform;
|
||||||
|
import io.metersphere.commons.exception.MSException;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.track.request.testcase.IssuesRequest;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ZentaoPlatform extends AbstractIssuePlatform {
|
||||||
|
/**
|
||||||
|
* zentao account
|
||||||
|
*/
|
||||||
|
private final String account;
|
||||||
|
/**
|
||||||
|
* zentao password
|
||||||
|
*/
|
||||||
|
private final String password;
|
||||||
|
/**
|
||||||
|
* zentao url eg:http://x.x.x.x/zentao
|
||||||
|
*/
|
||||||
|
private final String url;
|
||||||
|
|
||||||
|
public ZentaoPlatform(IssuesRequest issuesRequest) {
|
||||||
|
super(issuesRequest);
|
||||||
|
String config = getPlatformConfig(IssuesManagePlatform.Zentao.toString());
|
||||||
|
JSONObject object = JSON.parseObject(config);
|
||||||
|
this.account = object.getString("account");
|
||||||
|
this.password = object.getString("password");
|
||||||
|
this.url = object.getString("url");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getProjectId() {
|
||||||
|
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
|
||||||
|
Project project = projectService.getProjectById(testCase.getProjectId());
|
||||||
|
return project.getZentaoId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Issues> getIssue() {
|
||||||
|
List<Issues> list = new ArrayList<>();
|
||||||
|
|
||||||
|
TestCaseIssuesExample example = new TestCaseIssuesExample();
|
||||||
|
example.createCriteria().andTestCaseIdEqualTo(testCaseId);
|
||||||
|
|
||||||
|
List<Issues> issues = extIssuesMapper.getIssues(testCaseId, IssuesManagePlatform.Zentao.toString());
|
||||||
|
|
||||||
|
List<String> issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList());
|
||||||
|
issuesIds.forEach(issuesId -> {
|
||||||
|
Issues dto = getZentaoIssues(issuesId);
|
||||||
|
if (StringUtils.isBlank(dto.getId())) {
|
||||||
|
// 缺陷不存在,解除用例和缺陷的关联
|
||||||
|
TestCaseIssuesExample issuesExample = new TestCaseIssuesExample();
|
||||||
|
issuesExample.createCriteria()
|
||||||
|
.andTestCaseIdEqualTo(testCaseId)
|
||||||
|
.andIssuesIdEqualTo(issuesId);
|
||||||
|
testCaseIssuesMapper.deleteByExample(issuesExample);
|
||||||
|
issuesMapper.deleteByPrimaryKey(issuesId);
|
||||||
|
} else {
|
||||||
|
dto.setPlatform(IssuesManagePlatform.Zentao.toString());
|
||||||
|
// 缺陷状态为 关闭,则不显示
|
||||||
|
if (!StringUtils.equals("closed", dto.getStatus())) {
|
||||||
|
list.add(dto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Issues getZentaoIssues(String bugId) {
|
||||||
|
String session = login();
|
||||||
|
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(new HttpHeaders());
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
try {
|
||||||
|
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "api-getModel-bug-getById-bugID={bugId}?zentaosid=" + session,
|
||||||
|
HttpMethod.POST, requestEntity, String.class, bugId);
|
||||||
|
String body = responseEntity.getBody();
|
||||||
|
JSONObject obj = JSONObject.parseObject(body);
|
||||||
|
|
||||||
|
LogUtil.info("bug id is " + bugId + obj);
|
||||||
|
|
||||||
|
if (obj != null) {
|
||||||
|
JSONObject bug = obj.getJSONObject("data");
|
||||||
|
String id = bug.getString("id");
|
||||||
|
String title = bug.getString("title");
|
||||||
|
String description = bug.getString("steps");
|
||||||
|
Long createTime = bug.getLong("openedDate");
|
||||||
|
String status = bug.getString("status");
|
||||||
|
String reporter = bug.getString("openedBy");
|
||||||
|
int deleted = bug.getInteger("deleted");
|
||||||
|
if (deleted == 1) {
|
||||||
|
return new Issues();
|
||||||
|
}
|
||||||
|
Issues issues = new Issues();
|
||||||
|
issues.setId(id);
|
||||||
|
issues.setTitle(title);
|
||||||
|
issues.setDescription(description);
|
||||||
|
issues.setCreateTime(createTime);
|
||||||
|
issues.setStatus(status);
|
||||||
|
issues.setReporter(reporter);
|
||||||
|
return issues;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error("get zentao bug fail " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Issues();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addIssue(IssuesRequest issuesRequest) {
|
||||||
|
|
||||||
|
String session = login();
|
||||||
|
String projectId = getProjectId();
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(projectId)) {
|
||||||
|
MSException.throwException("add zentao bug fail, project zentao id is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(session)) {
|
||||||
|
MSException.throwException("session is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
||||||
|
paramMap.add("product", projectId);
|
||||||
|
paramMap.add("title", issuesRequest.getTitle());
|
||||||
|
paramMap.add("steps", issuesRequest.getContent());
|
||||||
|
if (!CollectionUtils.isEmpty(issuesRequest.getZentaoBuilds())) {
|
||||||
|
List<String> builds = issuesRequest.getZentaoBuilds();
|
||||||
|
builds.forEach(build -> {
|
||||||
|
paramMap.add("openedBuild[]", build);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paramMap.add("openedBuild", "trunk");
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(issuesRequest.getZentaoUser())) {
|
||||||
|
paramMap.add("assignedTo", issuesRequest.getZentaoUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(paramMap, new HttpHeaders());
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "api-getModel-bug-create.json?zentaosid=" + session, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
String body = responseEntity.getBody();
|
||||||
|
JSONObject obj = JSONObject.parseObject(body);
|
||||||
|
|
||||||
|
LogUtil.info("add zentao bug " + obj);
|
||||||
|
|
||||||
|
if (obj != null) {
|
||||||
|
JSONObject data = obj.getJSONObject("data");
|
||||||
|
String id = data.getString("id");
|
||||||
|
if (StringUtils.isNotBlank(id)) {
|
||||||
|
// 用例与第三方缺陷平台中的缺陷关联
|
||||||
|
TestCaseIssues testCaseIssues = new TestCaseIssues();
|
||||||
|
testCaseIssues.setId(UUID.randomUUID().toString());
|
||||||
|
testCaseIssues.setIssuesId(id);
|
||||||
|
testCaseIssues.setTestCaseId(testCaseId);
|
||||||
|
testCaseIssuesMapper.insert(testCaseIssues);
|
||||||
|
|
||||||
|
IssuesExample issuesExample = new IssuesExample();
|
||||||
|
issuesExample.createCriteria().andIdEqualTo(id)
|
||||||
|
.andPlatformEqualTo(IssuesManagePlatform.Zentao.toString());
|
||||||
|
if (issuesMapper.selectByExample(issuesExample).size() <= 0) {
|
||||||
|
// 插入缺陷表
|
||||||
|
Issues issues = new Issues();
|
||||||
|
issues.setId(id);
|
||||||
|
issues.setPlatform(IssuesManagePlatform.Zentao.toString());
|
||||||
|
issuesMapper.insert(issues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteIssue(String id) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testAuth() {
|
||||||
|
try {
|
||||||
|
login();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
|
MSException.throwException("验证失败!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String login() {
|
||||||
|
String session = getSession();
|
||||||
|
String loginUrl = url + "user-login.json?zentaosid=" + session;
|
||||||
|
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
||||||
|
paramMap.add("account", account);
|
||||||
|
paramMap.add("password", password);
|
||||||
|
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(paramMap, new HttpHeaders());
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
ResponseEntity<String> responseEntity = restTemplate.exchange(loginUrl, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
String body = responseEntity.getBody();
|
||||||
|
JSONObject obj = JSONObject.parseObject(body);
|
||||||
|
JSONObject user = obj.getJSONObject("user");
|
||||||
|
if (user == null) {
|
||||||
|
LogUtil.error("login fail");
|
||||||
|
LogUtil.error(obj);
|
||||||
|
// 登录失败,获取的session无效,置空session
|
||||||
|
MSException.throwException("zentao login fail");
|
||||||
|
}
|
||||||
|
String username = user.getString("account");
|
||||||
|
if (!StringUtils.equals(username, account)) {
|
||||||
|
LogUtil.error("login fail,inconsistent users");
|
||||||
|
MSException.throwException("zentao login fail");
|
||||||
|
}
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSession() {
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(new HttpHeaders());
|
||||||
|
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "api-getsessionid.json", HttpMethod.GET, requestEntity, String.class);
|
||||||
|
String body = responseEntity.getBody();
|
||||||
|
JSONObject obj = JSONObject.parseObject(body);
|
||||||
|
JSONObject data = obj.getJSONObject("data");
|
||||||
|
String session = data.getString("sessionID");
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PlatformUser> getPlatformUser() {
|
||||||
|
|
||||||
|
String session = login();
|
||||||
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
|
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(httpHeaders);
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "api-getModel-user-getList?zentaosid=" + session,
|
||||||
|
HttpMethod.GET, requestEntity, String.class);
|
||||||
|
String body = responseEntity.getBody();
|
||||||
|
JSONObject obj = JSONObject.parseObject(body);
|
||||||
|
|
||||||
|
LogUtil.info("zentao user " + obj);
|
||||||
|
|
||||||
|
JSONArray data = obj.getJSONArray("data");
|
||||||
|
|
||||||
|
List<PlatformUser> users = new ArrayList<>();
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
JSONObject o = data.getJSONObject(i);
|
||||||
|
PlatformUser platformUser = new PlatformUser();
|
||||||
|
String account = o.getString("account");
|
||||||
|
String username = o.getString("realname");
|
||||||
|
platformUser.setName(username);
|
||||||
|
platformUser.setUser(account);
|
||||||
|
users.add(platformUser);
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ZentaoBuild> getBuilds() {
|
||||||
|
String session = login();
|
||||||
|
String projectId = getProjectId();
|
||||||
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
|
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(httpHeaders);
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "api-getModel-build-getProductBuildPairs-productID={projectId}?zentaosid=" + session,
|
||||||
|
HttpMethod.GET, requestEntity, String.class, projectId);
|
||||||
|
String body = responseEntity.getBody();
|
||||||
|
JSONObject obj = JSONObject.parseObject(body);
|
||||||
|
|
||||||
|
LogUtil.info("zentao builds" + obj);
|
||||||
|
|
||||||
|
JSONObject data = obj.getJSONObject("data");
|
||||||
|
Map<String,Object> maps = data.getInnerMap();
|
||||||
|
|
||||||
|
List<ZentaoBuild> list = new ArrayList<>();
|
||||||
|
for (Map.Entry map : maps.entrySet()) {
|
||||||
|
ZentaoBuild build = new ZentaoBuild();
|
||||||
|
String id = (String) map.getKey();
|
||||||
|
if (StringUtils.isNotBlank(id)) {
|
||||||
|
build.setId((String) map.getKey());
|
||||||
|
build.setName((String) map.getValue());
|
||||||
|
list.add(build);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package io.metersphere.track.issue;
|
||||||
|
|
||||||
|
import io.metersphere.commons.utils.EncryptUtils;
|
||||||
|
|
||||||
|
public class ZentaoUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param code Zentao 应用代号
|
||||||
|
* @param key Zentao 密钥
|
||||||
|
* @return token
|
||||||
|
*/
|
||||||
|
public static String getToken(String code, String key, String time) {
|
||||||
|
return (String) EncryptUtils.md5Encrypt(code + key + time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param url Zentao url
|
||||||
|
* @param code Zentao 应用代号
|
||||||
|
* @param key Zentao 密钥
|
||||||
|
* @return url
|
||||||
|
*/
|
||||||
|
public static String getUrl(String url, String code, String key) {
|
||||||
|
String time = String.valueOf(System.currentTimeMillis());;
|
||||||
|
return url + "api.php?" + "code=" + code + "&time=" + time + "&token=" + getToken(code, key, time);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,4 +13,12 @@ public class IssuesRequest {
|
||||||
private String projectId;
|
private String projectId;
|
||||||
private String testCaseId;
|
private String testCaseId;
|
||||||
private List<String> tapdUsers;
|
private List<String> tapdUsers;
|
||||||
|
/**
|
||||||
|
* zentao bug 处理人
|
||||||
|
*/
|
||||||
|
private String zentaoUser;
|
||||||
|
/**
|
||||||
|
* zentao bug 影响版本
|
||||||
|
*/
|
||||||
|
private List<String> zentaoBuilds;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,7 @@ import io.metersphere.notice.service.NoticeService;
|
||||||
import io.metersphere.notice.service.WxChatTaskService;
|
import io.metersphere.notice.service.WxChatTaskService;
|
||||||
import io.metersphere.service.IntegrationService;
|
import io.metersphere.service.IntegrationService;
|
||||||
import io.metersphere.service.ProjectService;
|
import io.metersphere.service.ProjectService;
|
||||||
import io.metersphere.track.issue.AbstractIssuePlatform;
|
import io.metersphere.track.issue.*;
|
||||||
import io.metersphere.track.issue.IssueFactory;
|
|
||||||
import io.metersphere.track.issue.PlatformUser;
|
|
||||||
import io.metersphere.track.request.testcase.IssuesRequest;
|
import io.metersphere.track.request.testcase.IssuesRequest;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -63,9 +61,11 @@ public class IssuesService {
|
||||||
|
|
||||||
boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString());
|
boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString());
|
||||||
boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString());
|
boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString());
|
||||||
|
boolean zentao = isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString());
|
||||||
|
|
||||||
String tapdId = getTapdProjectId(issuesRequest.getTestCaseId());
|
String tapdId = getTapdProjectId(issuesRequest.getTestCaseId());
|
||||||
String jiraKey = getJiraProjectKey(issuesRequest.getTestCaseId());
|
String jiraKey = getJiraProjectKey(issuesRequest.getTestCaseId());
|
||||||
|
String zentaoId = getZentaoProjectId(issuesRequest.getTestCaseId());
|
||||||
|
|
||||||
List<String> platforms = new ArrayList<>();
|
List<String> platforms = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -82,7 +82,13 @@ public class IssuesService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey)) {
|
if (zentao) {
|
||||||
|
if (StringUtils.isNotBlank(zentaoId)) {
|
||||||
|
platforms.add(IssuesManagePlatform.Zentao.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey) && StringUtils.isBlank(zentaoId)) {
|
||||||
platforms.add("LOCAL");
|
platforms.add("LOCAL");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +128,7 @@ public class IssuesService {
|
||||||
|
|
||||||
boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString());
|
boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString());
|
||||||
boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString());
|
boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString());
|
||||||
|
boolean zentao = isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString());
|
||||||
|
|
||||||
List<String> platforms = new ArrayList<>();
|
List<String> platforms = new ArrayList<>();
|
||||||
if (tapd) {
|
if (tapd) {
|
||||||
|
@ -140,6 +147,13 @@ public class IssuesService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (zentao) {
|
||||||
|
String zentaoId = getZentaoProjectId(caseId);
|
||||||
|
if (StringUtils.isNotBlank(zentaoId)) {
|
||||||
|
platforms.add(IssuesManagePlatform.Zentao.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
platforms.add("LOCAL");
|
platforms.add("LOCAL");
|
||||||
IssuesRequest issueRequest = new IssuesRequest();
|
IssuesRequest issueRequest = new IssuesRequest();
|
||||||
issueRequest.setTestCaseId(caseId);
|
issueRequest.setTestCaseId(caseId);
|
||||||
|
@ -152,18 +166,24 @@ public class IssuesService {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTapdProjectId(String testCaseId) {
|
private String getTapdProjectId(String testCaseId) {
|
||||||
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
|
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
|
||||||
Project project = projectService.getProjectById(testCase.getProjectId());
|
Project project = projectService.getProjectById(testCase.getProjectId());
|
||||||
return project.getTapdId();
|
return project.getTapdId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getJiraProjectKey(String testCaseId) {
|
private String getJiraProjectKey(String testCaseId) {
|
||||||
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
|
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
|
||||||
Project project = projectService.getProjectById(testCase.getProjectId());
|
Project project = projectService.getProjectById(testCase.getProjectId());
|
||||||
return project.getJiraKey();
|
return project.getJiraKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getZentaoProjectId(String testCaseId) {
|
||||||
|
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
|
||||||
|
Project project = projectService.getProjectById(testCase.getProjectId());
|
||||||
|
return project.getZentaoId();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否关联平台
|
* 是否关联平台
|
||||||
*/
|
*/
|
||||||
|
@ -189,6 +209,13 @@ public class IssuesService {
|
||||||
return platform.getPlatformUser();
|
return platform.getPlatformUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<PlatformUser> getZentaoUsers(String caseId) {
|
||||||
|
IssuesRequest issueRequest = new IssuesRequest();
|
||||||
|
issueRequest.setTestCaseId(caseId);
|
||||||
|
AbstractIssuePlatform platform = IssueFactory.createPlatform(IssuesManagePlatform.Zentao.name(), issueRequest);
|
||||||
|
return platform.getPlatformUser();
|
||||||
|
}
|
||||||
|
|
||||||
public void deleteIssue(String id) {
|
public void deleteIssue(String id) {
|
||||||
issuesMapper.deleteByPrimaryKey(id);
|
issuesMapper.deleteByPrimaryKey(id);
|
||||||
}
|
}
|
||||||
|
@ -200,4 +227,11 @@ public class IssuesService {
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ZentaoBuild> getZentaoBuilds(String caseId) {
|
||||||
|
IssuesRequest issueRequest = new IssuesRequest();
|
||||||
|
issueRequest.setTestCaseId(caseId);
|
||||||
|
ZentaoPlatform platform = (ZentaoPlatform) IssueFactory.createPlatform(IssuesManagePlatform.Zentao.name(), issueRequest);
|
||||||
|
return platform.getBuilds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -457,12 +457,19 @@ public class TestCaseService {
|
||||||
if (t.getMethod().equals("manual")) {
|
if (t.getMethod().equals("manual")) {
|
||||||
String steps = t.getSteps();
|
String steps = t.getSteps();
|
||||||
String setp = "";
|
String setp = "";
|
||||||
|
setp = steps;
|
||||||
|
JSONArray jsonArray = null;
|
||||||
|
|
||||||
|
//解决旧版本保存用例导出报错
|
||||||
|
try {
|
||||||
|
jsonArray = JSON.parseArray(setp);
|
||||||
|
} catch (Exception e) {
|
||||||
if (steps.contains("null") && !steps.contains("\"null\"")) {
|
if (steps.contains("null") && !steps.contains("\"null\"")) {
|
||||||
setp = steps.replace("null", "\"\"");
|
setp = steps.replace("null", "\"\"");
|
||||||
} else {
|
jsonArray = JSON.parseArray(setp);
|
||||||
setp = steps;
|
|
||||||
}
|
}
|
||||||
JSONArray jsonArray = JSON.parseArray(setp);
|
}
|
||||||
|
|
||||||
for (int j = 0; j < jsonArray.size(); j++) {
|
for (int j = 0; j < jsonArray.size(); j++) {
|
||||||
int num = j + 1;
|
int num = j + 1;
|
||||||
step.append(num + "." + jsonArray.getJSONObject(j).getString("desc") + "\n");
|
step.append(num + "." + jsonArray.getJSONObject(j).getString("desc") + "\n");
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE load_test_report
|
||||||
|
ADD file_id VARCHAR(50) NULL;
|
|
@ -0,0 +1,2 @@
|
||||||
|
INSERT INTO role (id, name, description, type, create_time, update_time)
|
||||||
|
VALUES ('org_member', '组织成员', NULL, NULL, unix_timestamp() * 1000, unix_timestamp() * 1000);
|
|
@ -0,0 +1 @@
|
||||||
|
alter table project add zentao_id varchar(50) null;
|
|
@ -0,0 +1,4 @@
|
||||||
|
alter table issues drop primary key;
|
||||||
|
alter table issues
|
||||||
|
add constraint issues_pk
|
||||||
|
primary key (id, platform);
|
|
@ -170,6 +170,8 @@ task_defect_notification=Task defect notification
|
||||||
task_notification=Jenkins Task notification
|
task_notification=Jenkins Task notification
|
||||||
task_notification_=Timing task result notification
|
task_notification_=Timing task result notification
|
||||||
api_definition_url_not_repeating=The interface request address already exists
|
api_definition_url_not_repeating=The interface request address already exists
|
||||||
|
task_notification_jenkins=Jenkins Task notification
|
||||||
|
task_notification=Result notification
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -171,3 +171,5 @@ task_defect_notification=缺陷任务通知
|
||||||
task_notification=jenkins任务通知
|
task_notification=jenkins任务通知
|
||||||
task_notification_=定时任务结果通知
|
task_notification_=定时任务结果通知
|
||||||
api_definition_url_not_repeating=接口请求地址已经存在
|
api_definition_url_not_repeating=接口请求地址已经存在
|
||||||
|
task_notification_jenkins=jenkins任务通知
|
||||||
|
task_notification=任务通知
|
|
@ -169,6 +169,9 @@ check_owner_comment=當前用戶沒有操作此評論的權限
|
||||||
upload_content_is_null=導入內容為空
|
upload_content_is_null=導入內容為空
|
||||||
test_plan_notification=測試計畫通知
|
test_plan_notification=測試計畫通知
|
||||||
task_defect_notification=缺陷任務通知
|
task_defect_notification=缺陷任務通知
|
||||||
|
task_notification_jenkins=jenkins任務通知
|
||||||
|
task_notification=任務通知
|
||||||
|
|
||||||
task_notification=jenkins任務通知
|
task_notification=jenkins任務通知
|
||||||
task_notification_=定時任務通知
|
task_notification_=定時任務通知
|
||||||
api_definition_url_not_repeating=接口請求地址已經存在
|
api_definition_url_not_repeating=接口請求地址已經存在
|
||||||
|
|
|
@ -57,9 +57,9 @@ export default {
|
||||||
if (header.default !== undefined) {
|
if (header.default !== undefined) {
|
||||||
this.licenseHeader = "LicenseMessage";
|
this.licenseHeader = "LicenseMessage";
|
||||||
}
|
}
|
||||||
// 是否显示校验信息
|
|
||||||
if (display.default !== undefined) {
|
if (display.default !== undefined) {
|
||||||
display.default.valid(this);
|
display.default.showHome(this);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
window.location.href = "/login"
|
window.location.href = "/login"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ms-container v-loading="loading" :element-loading-text="$t('api_report.running')">
|
<ms-container v-loading="loading">
|
||||||
<ms-main-container>
|
<ms-main-container>
|
||||||
<el-card>
|
<el-card>
|
||||||
<section class="report-container" v-if="this.report.testId">
|
<section class="report-container" v-if="this.report.testId">
|
||||||
|
@ -23,10 +23,12 @@
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="16" style="margin-top: 40px;">
|
<el-col :span="16" style="margin-top: 40px;">
|
||||||
<ms-request-result-tail v-if="isRequestResult" :request-type="requestType" :request="request" :scenario-name="scenarioName"/>
|
<ms-request-result-tail v-if="isRequestResult" :request-type="requestType" :request="request"
|
||||||
|
:scenario-name="scenarioName"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<ms-api-report-export v-if="reportExportVisible" id="apiTestReport" :title="report.testName" :content="content" :total-time="totalTime"/>
|
<ms-api-report-export v-if="reportExportVisible" id="apiTestReport" :title="report.testName"
|
||||||
|
:content="content" :total-time="totalTime"/>
|
||||||
</main>
|
</main>
|
||||||
</section>
|
</section>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
@ -44,7 +46,7 @@ import MsScenarioResults from "./components/ScenarioResults";
|
||||||
import MsContainer from "@/business/components/common/components/MsContainer";
|
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||||
import MsApiReportExport from "./ApiReportExport";
|
import MsApiReportExport from "./ApiReportExport";
|
||||||
import {exportPdf} from "../../../../common/js/utils";
|
import {exportPdf} from "@/common/js/utils";
|
||||||
import html2canvas from "html2canvas";
|
import html2canvas from "html2canvas";
|
||||||
import MsApiReportViewHeader from "./ApiReportViewHeader";
|
import MsApiReportViewHeader from "./ApiReportViewHeader";
|
||||||
import {RequestFactory} from "../test/model/ScenarioModel";
|
import {RequestFactory} from "../test/model/ScenarioModel";
|
||||||
|
@ -104,7 +106,7 @@ export default {
|
||||||
try {
|
try {
|
||||||
this.content = JSON.parse(this.report.content);
|
this.content = JSON.parse(this.report.content);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(this.report.content)
|
// console.log(this.report.content)
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
this.getFails();
|
this.getFails();
|
||||||
|
@ -158,14 +160,12 @@ export default {
|
||||||
let reset = this.exportReportReset;
|
let reset = this.exportReportReset;
|
||||||
|
|
||||||
this.$nextTick(function () {
|
this.$nextTick(function () {
|
||||||
setTimeout(() => {
|
|
||||||
html2canvas(document.getElementById('apiTestReport'), {
|
html2canvas(document.getElementById('apiTestReport'), {
|
||||||
scale: 2
|
// scale: 2,
|
||||||
}).then(function(canvas) {
|
}).then(function (canvas) {
|
||||||
exportPdf(name, [canvas]);
|
exportPdf(name, [canvas]);
|
||||||
reset();
|
reset();
|
||||||
});
|
});
|
||||||
}, 1000);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
exportReportReset() {
|
exportReportReset() {
|
||||||
|
@ -196,35 +196,35 @@ export default {
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.report-container {
|
.report-container {
|
||||||
height: calc(100vh - 155px);
|
height: calc(100vh - 155px);
|
||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-header {
|
.report-header {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-header a {
|
.report-header a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-header .time {
|
.report-header .time {
|
||||||
color: #909399;
|
color: #909399;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-container .fail {
|
.report-container .fail {
|
||||||
color: #F56C6C;
|
color: #F56C6C;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-container .is-active .fail {
|
.report-container .is-active .fail {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.export-button {
|
.export-button {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -118,7 +118,7 @@
|
||||||
validateDomain(domain) {
|
validateDomain(domain) {
|
||||||
let strRegex = "^(?=^.{3,255}$)(http(s)?:\\/\\/)?(www\\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\\d+)*(\\/\\w+\\.\\w+)*$";
|
let strRegex = "^(?=^.{3,255}$)(http(s)?:\\/\\/)?(www\\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\\d+)*(\\/\\w+\\.\\w+)*$";
|
||||||
const re = new RegExp(strRegex);
|
const re = new RegExp(strRegex);
|
||||||
if (re.test(domain) && domain.length < 26) {
|
if (re.test(domain) && domain.length < 67) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this.$warning(this.$t('load_test.input_domain'));
|
this.$warning(this.$t('load_test.input_domain'));
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div>
|
<div>
|
||||||
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
|
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
|
||||||
<el-col>
|
<el-col>
|
||||||
<el-input :disabled="isReadOnly" :value="value" v-bind="$attrs" step="100" size="small" type="number" @change="change" @input="input"
|
<el-input :disabled="isReadOnly" :value="value" v-bind="$attrs" step="100" size="small" type="number" @change="change" @input="input" :min="0"
|
||||||
:placeholder="$t('api_test.request.assertions.response_in_time')"/>
|
:placeholder="$t('api_test.request.assertions.response_in_time')"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col class="assertion-btn">
|
<el-col class="assertion-btn">
|
||||||
|
@ -35,17 +35,28 @@
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
add() {
|
add() {
|
||||||
|
if (this.validate()) {
|
||||||
this.duration.value = this.value;
|
this.duration.value = this.value;
|
||||||
this.callback();
|
this.callback();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
remove() {
|
remove() {
|
||||||
this.duration.value = undefined;
|
this.duration.value = undefined;
|
||||||
},
|
},
|
||||||
change(value) {
|
change(value) {
|
||||||
|
if (this.validate()) {
|
||||||
this.$emit('change', value);
|
this.$emit('change', value);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
input(value) {
|
input(value) {
|
||||||
this.$emit('input', value);
|
this.$emit('input', value);
|
||||||
|
},
|
||||||
|
validate() {
|
||||||
|
if (Number(this.value) < 0 || this.value=='') {
|
||||||
|
this.$error(this.$t('commons.formatErr'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initWebSocket() {
|
initWebSocket() {
|
||||||
window.console.log("init WebSocket");
|
// window.console.log("init WebSocket");
|
||||||
const uri = "ws://" + window.location.host + "/socket";
|
const uri = "ws://" + window.location.host + "/socket";
|
||||||
this.websocket = new WebSocket(uri);
|
this.websocket = new WebSocket(uri);
|
||||||
this.websocket.onmessage = this.onMessage;
|
this.websocket.onmessage = this.onMessage;
|
||||||
|
@ -36,10 +36,10 @@
|
||||||
window.console.error(e)
|
window.console.error(e)
|
||||||
},
|
},
|
||||||
onMessage(e) {
|
onMessage(e) {
|
||||||
window.console.log(e.data)
|
// window.console.log(e.data)
|
||||||
},
|
},
|
||||||
onClose(e) {
|
onClose(e) {
|
||||||
window.console.log('断开连接', e);
|
// window.console.log('断开连接', e);
|
||||||
},
|
},
|
||||||
send(Data) {
|
send(Data) {
|
||||||
this.websocket.send(Data);
|
this.websocket.send(Data);
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
<el-button :disabled="isReadOnly" type="info" plain size="mini" @click="handleExport(reportName)">
|
<el-button :disabled="isReadOnly" type="info" plain size="mini" @click="handleExport(reportName)">
|
||||||
{{ $t('test_track.plan_view.export_report') }}
|
{{ $t('test_track.plan_view.export_report') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button :disabled="isReadOnly" type="warning" plain size="mini" @click="downloadJtl()">
|
||||||
|
{{ $t('report.downloadJtl') }}
|
||||||
|
</el-button>
|
||||||
|
|
||||||
<!--<el-button :disabled="isReadOnly" type="warning" plain size="mini">-->
|
<!--<el-button :disabled="isReadOnly" type="warning" plain size="mini">-->
|
||||||
<!--{{$t('report.compare')}}-->
|
<!--{{$t('report.compare')}}-->
|
||||||
|
@ -95,6 +98,7 @@ import MsMainContainer from "../../common/components/MsMainContainer";
|
||||||
import {checkoutTestManagerOrTestUser, exportPdf} from "@/common/js/utils";
|
import {checkoutTestManagerOrTestUser, exportPdf} from "@/common/js/utils";
|
||||||
import html2canvas from 'html2canvas';
|
import html2canvas from 'html2canvas';
|
||||||
import MsPerformanceReportExport from "./PerformanceReportExport";
|
import MsPerformanceReportExport from "./PerformanceReportExport";
|
||||||
|
import {Message} from "element-ui";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -234,10 +238,10 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onOpen() {
|
onOpen() {
|
||||||
window.console.log("socket opening.");
|
// window.console.log("socket opening.");
|
||||||
},
|
},
|
||||||
onError(e) {
|
onError(e) {
|
||||||
window.console.error(e)
|
// window.console.error(e)
|
||||||
},
|
},
|
||||||
onMessage(e) {
|
onMessage(e) {
|
||||||
this.$set(this.report, "refresh", e.data); // 触发刷新
|
this.$set(this.report, "refresh", e.data); // 触发刷新
|
||||||
|
@ -249,7 +253,7 @@ export default {
|
||||||
this.$set(this.report, "status", 'Running');
|
this.$set(this.report, "status", 'Running');
|
||||||
this.status = 'Running';
|
this.status = 'Running';
|
||||||
this.initReportTimeInfo();
|
this.initReportTimeInfo();
|
||||||
window.console.log('receive a message:', e.data);
|
// window.console.log('receive a message:', e.data);
|
||||||
},
|
},
|
||||||
onClose(e) {
|
onClose(e) {
|
||||||
if (e.code === 1005) {
|
if (e.code === 1005) {
|
||||||
|
@ -259,7 +263,7 @@ export default {
|
||||||
this.$set(this.report, "refresh", Math.random()); // 触发刷新
|
this.$set(this.report, "refresh", Math.random()); // 触发刷新
|
||||||
this.$set(this.report, "status", 'Completed');
|
this.$set(this.report, "status", 'Completed');
|
||||||
this.initReportTimeInfo();
|
this.initReportTimeInfo();
|
||||||
window.console.log("socket closed.");
|
// window.console.log("socket closed.");
|
||||||
},
|
},
|
||||||
handleExport(name) {
|
handleExport(name) {
|
||||||
this.result.loading = true;
|
this.result.loading = true;
|
||||||
|
@ -267,20 +271,46 @@ export default {
|
||||||
let reset = this.exportReportReset;
|
let reset = this.exportReportReset;
|
||||||
|
|
||||||
this.$nextTick(function () {
|
this.$nextTick(function () {
|
||||||
setTimeout(() => {
|
|
||||||
html2canvas(document.getElementById('performanceReportExport'), {
|
html2canvas(document.getElementById('performanceReportExport'), {
|
||||||
scale: 2
|
// scale: 2
|
||||||
}).then(function (canvas) {
|
}).then(function (canvas) {
|
||||||
exportPdf(name, [canvas]);
|
exportPdf(name, [canvas]);
|
||||||
reset();
|
reset();
|
||||||
});
|
});
|
||||||
}, 1000);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
exportReportReset() {
|
exportReportReset() {
|
||||||
this.reportExportVisible = false;
|
this.reportExportVisible = false;
|
||||||
this.result.loading = false;
|
this.result.loading = false;
|
||||||
},
|
},
|
||||||
|
downloadJtl() {
|
||||||
|
let config = {
|
||||||
|
url: "/performance/report/jtl/download/" + this.reportId,
|
||||||
|
method: 'get',
|
||||||
|
responseType: 'blob'
|
||||||
|
};
|
||||||
|
this.result = this.$request(config).then(response => {
|
||||||
|
const content = response.data;
|
||||||
|
const blob = new Blob([content]);
|
||||||
|
if ("download" in document.createElement("a")) {
|
||||||
|
// 非IE下载
|
||||||
|
// chrome/firefox
|
||||||
|
let aTag = document.createElement('a');
|
||||||
|
aTag.download = this.reportId + ".jtl";
|
||||||
|
aTag.href = URL.createObjectURL(blob);
|
||||||
|
aTag.click();
|
||||||
|
URL.revokeObjectURL(aTag.href)
|
||||||
|
} else {
|
||||||
|
// IE10+下载
|
||||||
|
navigator.msSaveBlob(blob, this.filename)
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
let text = e.response.data.text();
|
||||||
|
text.then((data) => {
|
||||||
|
Message.error({message: JSON.parse(data).message || e.message, showClose: true});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.isReadOnly = false;
|
this.isReadOnly = false;
|
||||||
|
@ -328,7 +358,7 @@ export default {
|
||||||
});
|
});
|
||||||
this.initWebSocket();
|
this.initWebSocket();
|
||||||
} else {
|
} else {
|
||||||
console.log("close socket.");
|
// console.log("close socket.");
|
||||||
this.websocket.close() //离开路由之后断开websocket连接
|
this.websocket.close() //离开路由之后断开websocket连接
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,11 @@ export default {
|
||||||
this.threadGroups[i].rampUpTime = item.value;
|
this.threadGroups[i].rampUpTime = item.value;
|
||||||
break;
|
break;
|
||||||
case DURATION:
|
case DURATION:
|
||||||
|
if (item.unit) {
|
||||||
this.threadGroups[i].duration = item.value;
|
this.threadGroups[i].duration = item.value;
|
||||||
|
} else {
|
||||||
|
this.threadGroups[i].duration = item.value * 60;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case STEPS:
|
case STEPS:
|
||||||
this.threadGroups[i].step = item.value;
|
this.threadGroups[i].step = item.value;
|
||||||
|
@ -154,7 +158,11 @@ export default {
|
||||||
this.threadGroups[0].rampUpTime = d.value;
|
this.threadGroups[0].rampUpTime = d.value;
|
||||||
break;
|
break;
|
||||||
case DURATION:
|
case DURATION:
|
||||||
|
if (d.unit) {
|
||||||
this.threadGroups[0].duration = d.value;
|
this.threadGroups[0].duration = d.value;
|
||||||
|
} else {
|
||||||
|
this.threadGroups[0].duration = d.value * 60;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case STEPS:
|
case STEPS:
|
||||||
this.threadGroups[0].step = d.value;
|
this.threadGroups[0].step = d.value;
|
||||||
|
@ -196,7 +204,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getJmxContent() {
|
getJmxContent() {
|
||||||
console.log(this.report.testId);
|
// console.log(this.report.testId);
|
||||||
if (!this.report.testId) {
|
if (!this.report.testId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,7 +191,11 @@ export default {
|
||||||
this.threadGroups[i].rampUpTime = item.value;
|
this.threadGroups[i].rampUpTime = item.value;
|
||||||
break;
|
break;
|
||||||
case DURATION:
|
case DURATION:
|
||||||
|
if (item.unit) {
|
||||||
this.threadGroups[i].duration = item.value;
|
this.threadGroups[i].duration = item.value;
|
||||||
|
} else {
|
||||||
|
this.threadGroups[i].duration = item.value * 60;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case STEPS:
|
case STEPS:
|
||||||
this.threadGroups[i].step = item.value;
|
this.threadGroups[i].step = item.value;
|
||||||
|
@ -216,7 +220,11 @@ export default {
|
||||||
this.threadGroups[0].rampUpTime = d.value;
|
this.threadGroups[0].rampUpTime = d.value;
|
||||||
break;
|
break;
|
||||||
case DURATION:
|
case DURATION:
|
||||||
|
if (d.unit) {
|
||||||
this.threadGroups[0].duration = d.value;
|
this.threadGroups[0].duration = d.value;
|
||||||
|
} else {
|
||||||
|
this.threadGroups[0].duration = d.value * 60;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case STEPS:
|
case STEPS:
|
||||||
this.threadGroups[0].step = d.value;
|
this.threadGroups[0].step = d.value;
|
||||||
|
@ -468,7 +476,7 @@ export default {
|
||||||
{key: TARGET_LEVEL, value: this.threadGroups[i].threadNumber},
|
{key: TARGET_LEVEL, value: this.threadGroups[i].threadNumber},
|
||||||
{key: RAMP_UP, value: this.threadGroups[i].rampUpTime},
|
{key: RAMP_UP, value: this.threadGroups[i].rampUpTime},
|
||||||
{key: STEPS, value: this.threadGroups[i].step},
|
{key: STEPS, value: this.threadGroups[i].step},
|
||||||
{key: DURATION, value: this.threadGroups[i].duration},
|
{key: DURATION, value: this.threadGroups[i].duration, unit: 'S'},
|
||||||
{key: RPS_LIMIT, value: this.threadGroups[i].rpsLimit},
|
{key: RPS_LIMIT, value: this.threadGroups[i].rpsLimit},
|
||||||
{key: RPS_LIMIT_ENABLE, value: this.threadGroups[i].rpsLimitEnable},
|
{key: RPS_LIMIT_ENABLE, value: this.threadGroups[i].rpsLimitEnable},
|
||||||
{key: HOLD, value: this.threadGroups[i].duration - this.threadGroups[i].rampUpTime},
|
{key: HOLD, value: this.threadGroups[i].duration - this.threadGroups[i].rampUpTime},
|
||||||
|
|
|
@ -63,6 +63,9 @@
|
||||||
<el-form-item :label="$t('project.jira_key')" v-if="jira">
|
<el-form-item :label="$t('project.jira_key')" v-if="jira">
|
||||||
<el-input v-model="form.jiraKey" autocomplete="off"></el-input>
|
<el-input v-model="form.jiraKey" autocomplete="off"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('project.zentao_id')" v-if="zentao">
|
||||||
|
<el-input v-model="form.zentaoId" autocomplete="off"></el-input>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
|
@ -116,6 +119,7 @@ export default {
|
||||||
items: [],
|
items: [],
|
||||||
tapd: false,
|
tapd: false,
|
||||||
jira: false,
|
jira: false,
|
||||||
|
zentao: false,
|
||||||
form: {},
|
form: {},
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 5,
|
pageSize: 5,
|
||||||
|
@ -194,6 +198,9 @@ export default {
|
||||||
if (platforms.indexOf("Jira") !== -1) {
|
if (platforms.indexOf("Jira") !== -1) {
|
||||||
this.jira = true;
|
this.jira = true;
|
||||||
}
|
}
|
||||||
|
if (platforms.indexOf("Zentao") !== -1) {
|
||||||
|
this.zentao = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -165,6 +165,11 @@
|
||||||
for (let i = 0; i < this.tableData.length; i++) {
|
for (let i = 0; i < this.tableData.length; i++) {
|
||||||
this.$get(url + "/" + encodeURIComponent(this.tableData[i].id), response => {
|
this.$get(url + "/" + encodeURIComponent(this.tableData[i].id), response => {
|
||||||
let roles = response.data;
|
let roles = response.data;
|
||||||
|
if (roles.length < 1) {
|
||||||
|
roles.push({
|
||||||
|
id : "org_member",
|
||||||
|
});
|
||||||
|
}
|
||||||
this.$set(this.tableData[i], "roles", roles);
|
this.$set(this.tableData[i], "roles", roles);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,10 +145,17 @@ export default {
|
||||||
data.isReadOnly = true;
|
data.isReadOnly = true;
|
||||||
if (data.type === 'EMAIL') {
|
if (data.type === 'EMAIL') {
|
||||||
data.isReadOnly = !data.isReadOnly
|
data.isReadOnly = !data.isReadOnly
|
||||||
|
data.webhook = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleEditTask(index,data){
|
handleEditTask(index,data) {
|
||||||
data.isSet = true
|
data.isSet = true
|
||||||
|
if (data.type === 'EMAIL') {
|
||||||
|
data.isReadOnly = false
|
||||||
|
data.webhook = ""
|
||||||
|
} else {
|
||||||
|
data.isReadOnly = true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleAddTaskModel(type) {
|
handleAddTaskModel(type) {
|
||||||
let Task = {};
|
let Task = {};
|
||||||
|
@ -178,7 +185,7 @@ export default {
|
||||||
handleAddTask(index, data) {
|
handleAddTask(index, data) {
|
||||||
|
|
||||||
if (data.event && data.userIds.length > 0 && data.type) {
|
if (data.event && data.userIds.length > 0 && data.type) {
|
||||||
console.log(data.type)
|
// console.log(data.type)
|
||||||
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
||||||
if (!data.webhook) {
|
if (!data.webhook) {
|
||||||
this.$warning(this.$t('organization.message.message_webhook'));
|
this.$warning(this.$t('organization.message.message_webhook'));
|
||||||
|
|
|
@ -147,6 +147,7 @@ export default {
|
||||||
data.isReadOnly = true;
|
data.isReadOnly = true;
|
||||||
if (data.type === 'EMAIL') {
|
if (data.type === 'EMAIL') {
|
||||||
data.isReadOnly = !data.isReadOnly
|
data.isReadOnly = !data.isReadOnly
|
||||||
|
data.webhook = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleAddTaskModel(type) {
|
handleAddTaskModel(type) {
|
||||||
|
@ -176,7 +177,7 @@ export default {
|
||||||
},
|
},
|
||||||
handleAddTask(index, data) {
|
handleAddTask(index, data) {
|
||||||
if (data.event && data.userIds.length > 0 && data.type) {
|
if (data.event && data.userIds.length > 0 && data.type) {
|
||||||
console.log(data.type)
|
// console.log(data.type)
|
||||||
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
||||||
if (!data.webhook) {
|
if (!data.webhook) {
|
||||||
this.$warning(this.$t('organization.message.message_webhook'));
|
this.$warning(this.$t('organization.message.message_webhook'));
|
||||||
|
@ -190,8 +191,15 @@ export default {
|
||||||
this.$warning(this.$t('organization.message.message'));
|
this.$warning(this.$t('organization.message.message'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleEditTask(index,data){
|
handleEditTask(index,data) {
|
||||||
data.isSet = true
|
data.isSet = true
|
||||||
|
if (data.type === 'EMAIL') {
|
||||||
|
data.isReadOnly = false
|
||||||
|
data.webhook = ""
|
||||||
|
} else {
|
||||||
|
data.isReadOnly = true
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
addTask(data) {
|
addTask(data) {
|
||||||
let list = []
|
let list = []
|
||||||
|
|
|
@ -140,7 +140,7 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
initForm(){
|
initForm(){
|
||||||
this.result = this.$get('/notice/search/message/'+this.testId, response => {
|
this.result = this.$get('/notice/search/message/'+this.testId, response => {
|
||||||
console.log(response.data);
|
// console.log(response.data);
|
||||||
this.form.scheduleTask = response.data;
|
this.form.scheduleTask = response.data;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -148,6 +148,7 @@ export default {
|
||||||
data.isReadOnly = true;
|
data.isReadOnly = true;
|
||||||
if (data.type === 'EMAIL') {
|
if (data.type === 'EMAIL') {
|
||||||
data.isReadOnly = !data.isReadOnly
|
data.isReadOnly = !data.isReadOnly
|
||||||
|
data.webhook = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleAddTaskModel(type) {
|
handleAddTaskModel(type) {
|
||||||
|
@ -164,13 +165,19 @@ export default {
|
||||||
this.form.scheduleTask.push(Task)
|
this.form.scheduleTask.push(Task)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleEditTask(index,data){
|
handleEditTask(index,data) {
|
||||||
data.isSet = true
|
data.isSet = true
|
||||||
data.testId=this.testId
|
data.testId = this.testId
|
||||||
|
if (data.type === 'EMAIL') {
|
||||||
|
data.isReadOnly = false
|
||||||
|
data.webhook = ""
|
||||||
|
} else {
|
||||||
|
data.isReadOnly = true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleAddTask(index, data) {
|
handleAddTask(index, data) {
|
||||||
if (data.event && data.userIds.length > 0 && data.type) {
|
if (data.event && data.userIds.length > 0 && data.type) {
|
||||||
console.log(data.type)
|
// console.log(data.type)
|
||||||
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
||||||
if (!data.webhook) {
|
if (!data.webhook) {
|
||||||
this.$warning(this.$t('organization.message.message_webhook'));
|
this.$warning(this.$t('organization.message.message_webhook'));
|
||||||
|
|
|
@ -151,10 +151,17 @@ export default {
|
||||||
data.isReadOnly = true;
|
data.isReadOnly = true;
|
||||||
if (data.type === 'EMAIL') {
|
if (data.type === 'EMAIL') {
|
||||||
data.isReadOnly = !data.isReadOnly
|
data.isReadOnly = !data.isReadOnly
|
||||||
|
data.webhook = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleEditTask(index,data){
|
handleEditTask(index,data) {
|
||||||
data.isSet = true
|
data.isSet = true
|
||||||
|
if (data.type === 'EMAIL') {
|
||||||
|
data.isReadOnly = false
|
||||||
|
data.webhook = ""
|
||||||
|
} else {
|
||||||
|
data.isReadOnly = true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleAddTaskModel(type) {
|
handleAddTaskModel(type) {
|
||||||
let Task = {};
|
let Task = {};
|
||||||
|
@ -184,7 +191,7 @@ export default {
|
||||||
handleAddTask(index, data) {
|
handleAddTask(index, data) {
|
||||||
|
|
||||||
if (data.event && data.userIds.length > 0 && data.type) {
|
if (data.event && data.userIds.length > 0 && data.type) {
|
||||||
console.log(data.type)
|
// console.log(data.type)
|
||||||
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
||||||
if (!data.webhook) {
|
if (!data.webhook) {
|
||||||
this.$warning(this.$t('organization.message.message_webhook'));
|
this.$warning(this.$t('organization.message.message_webhook'));
|
||||||
|
|
|
@ -152,10 +152,17 @@ export default {
|
||||||
data.isReadOnly = true;
|
data.isReadOnly = true;
|
||||||
if (data.type === 'EMAIL') {
|
if (data.type === 'EMAIL') {
|
||||||
data.isReadOnly = !data.isReadOnly
|
data.isReadOnly = !data.isReadOnly
|
||||||
|
data.webhook = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleEditTask(index,data){
|
handleEditTask(index,data) {
|
||||||
data.isSet = true
|
data.isSet = true
|
||||||
|
if (data.type === 'EMAIL') {
|
||||||
|
data.isReadOnly = false
|
||||||
|
data.webhook = ""
|
||||||
|
} else {
|
||||||
|
data.isReadOnly = true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleAddTaskModel(type) {
|
handleAddTaskModel(type) {
|
||||||
let Task = {};
|
let Task = {};
|
||||||
|
@ -185,7 +192,7 @@ export default {
|
||||||
handleAddTask(index, data) {
|
handleAddTask(index, data) {
|
||||||
|
|
||||||
if (data.event && data.userIds.length > 0 && data.type) {
|
if (data.event && data.userIds.length > 0 && data.type) {
|
||||||
console.log(data.type)
|
// console.log(data.type)
|
||||||
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
||||||
if (!data.webhook) {
|
if (!data.webhook) {
|
||||||
this.$warning(this.$t('organization.message.message_webhook'));
|
this.$warning(this.$t('organization.message.message_webhook'));
|
||||||
|
|
|
@ -3,12 +3,15 @@
|
||||||
<div style="width: 500px">
|
<div style="width: 500px">
|
||||||
<div style="margin-top: 20px;margin-bottom: 10px">{{ $t('organization.integration.basic_auth_info') }}</div>
|
<div style="margin-top: 20px;margin-bottom: 10px">{{ $t('organization.integration.basic_auth_info') }}</div>
|
||||||
<el-form :model="form" ref="form" label-width="120px" size="small" :disabled="show" :rules="rules">
|
<el-form :model="form" ref="form" label-width="120px" size="small" :disabled="show" :rules="rules">
|
||||||
<el-form-item :label="$t('organization.integration.app_name')" prop="account">
|
<el-form-item :label="$t('organization.integration.account')" prop="account">
|
||||||
<el-input v-model="form.account" :placeholder="$t('organization.integration.input_app_name')"/>
|
<el-input v-model="form.account" :placeholder="$t('organization.integration.input_api_account')"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('organization.integration.app_key')" prop="password">
|
<el-form-item :label="$t('organization.integration.password')" prop="password">
|
||||||
<el-input v-model="form.password" auto-complete="new-password"
|
<el-input v-model="form.password" auto-complete="new-password"
|
||||||
:placeholder="$t('organization.integration.input_app_key')" show-password/>
|
:placeholder="$t('organization.integration.input_api_password')" show-password/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('organization.integration.zentao_url')" prop="url">
|
||||||
|
<el-input v-model="form.url" :placeholder="$t('organization.integration.input_zentao_url')"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,14 +59,19 @@ export default {
|
||||||
rules: {
|
rules: {
|
||||||
account: {
|
account: {
|
||||||
required: true,
|
required: true,
|
||||||
message: this.$t('organization.integration.input_app_name'),
|
message: this.$t('organization.integration.input_api_account'),
|
||||||
trigger: ['change', 'blur']
|
trigger: ['change', 'blur']
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
required: true,
|
required: true,
|
||||||
message: this.$t('organization.integration.input_app_key'),
|
message: this.$t('organization.integration.input_api_password'),
|
||||||
trigger: ['change', 'blur']
|
trigger: ['change', 'blur']
|
||||||
}
|
},
|
||||||
|
url: {
|
||||||
|
required: true,
|
||||||
|
message: this.$t('organization.integration.input_zentao_url'),
|
||||||
|
trigger: ['change', 'blur']
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -71,12 +79,16 @@ export default {
|
||||||
save() {
|
save() {
|
||||||
this.$refs['form'].validate(valid => {
|
this.$refs['form'].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
let formatUrl = this.form.url.trim();
|
||||||
|
if (!formatUrl.endsWith('/')) {
|
||||||
|
formatUrl = formatUrl + '/';
|
||||||
|
}
|
||||||
const {lastOrganizationId} = getCurrentUser();
|
const {lastOrganizationId} = getCurrentUser();
|
||||||
let param = {};
|
let param = {};
|
||||||
let auth = {
|
let auth = {
|
||||||
account: this.form.account,
|
account: this.form.account,
|
||||||
password: this.form.password,
|
password: this.form.password,
|
||||||
|
url: formatUrl,
|
||||||
};
|
};
|
||||||
param.organizationId = lastOrganizationId;
|
param.organizationId = lastOrganizationId;
|
||||||
param.platform = ZEN_TAO;
|
param.platform = ZEN_TAO;
|
||||||
|
@ -106,6 +118,7 @@ export default {
|
||||||
let config = JSON.parse(data.configuration);
|
let config = JSON.parse(data.configuration);
|
||||||
this.$set(this.form, 'account', config.account);
|
this.$set(this.form, 'account', config.account);
|
||||||
this.$set(this.form, 'password', config.password);
|
this.$set(this.form, 'password', config.password);
|
||||||
|
this.$set(this.form, 'url', config.url);
|
||||||
} else {
|
} else {
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
|
@ -114,11 +127,14 @@ export default {
|
||||||
clear() {
|
clear() {
|
||||||
this.$set(this.form, 'account', '');
|
this.$set(this.form, 'account', '');
|
||||||
this.$set(this.form, 'password', '');
|
this.$set(this.form, 'password', '');
|
||||||
|
this.$set(this.form, 'url', '');
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.form.clearValidate();
|
this.$refs.form.clearValidate();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
testConnection() {
|
testConnection() {
|
||||||
|
this.$refs['form'].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
if (this.form.account && this.form.password) {
|
if (this.form.account && this.form.password) {
|
||||||
this.$parent.result = this.$get("issues/auth/" + ZEN_TAO, () => {
|
this.$parent.result = this.$get("issues/auth/" + ZEN_TAO, () => {
|
||||||
this.$success(this.$t('organization.integration.verified'));
|
this.$success(this.$t('organization.integration.verified'));
|
||||||
|
@ -127,6 +143,10 @@ export default {
|
||||||
this.$warning(this.$t('organization.integration.not_integrated'));
|
this.$warning(this.$t('organization.integration.not_integrated'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
cancelIntegration() {
|
cancelIntegration() {
|
||||||
if (this.form.account && this.form.password) {
|
if (this.form.account && this.form.password) {
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="source" :label="$t('user.source')"/>
|
<el-table-column prop="source" :label="$t('user.source')"/>
|
||||||
<el-table-column :label="$t('commons.operating')">
|
<el-table-column :label="$t('commons.operating')" min-width="120px">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<ms-table-operator @editClick="edit(scope.row)" @deleteClick="del(scope.row)">
|
<ms-table-operator @editClick="edit(scope.row)" @deleteClick="del(scope.row)">
|
||||||
<template v-slot:behind>
|
<template v-slot:behind>
|
||||||
|
@ -103,6 +103,21 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="role.id === 'org_member'">
|
||||||
|
<el-form-item :label="$t('organization.select_organization')"
|
||||||
|
:prop="'roles.' + index + '.ids'"
|
||||||
|
:rules="{required: true, message: $t('organization.select_organization'), trigger: 'change'}"
|
||||||
|
>
|
||||||
|
<el-select filterable v-model="role.ids" :placeholder="$t('organization.select_organization')" multiple>
|
||||||
|
<el-option
|
||||||
|
v-for="item in form.orgList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
<div v-if="role.id === 'test_manager'">
|
<div v-if="role.id === 'test_manager'">
|
||||||
<el-form-item :label="$t('workspace.select')"
|
<el-form-item :label="$t('workspace.select')"
|
||||||
:prop="'roles.' + index + '.ids'"
|
:prop="'roles.' + index + '.ids'"
|
||||||
|
@ -214,6 +229,21 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="role.id === 'org_member'">
|
||||||
|
<el-form-item :label="$t('organization.select_organization')"
|
||||||
|
:prop="'roles.' + index + '.ids'"
|
||||||
|
:rules="{required: true, message: $t('organization.select_organization'), trigger: 'change'}"
|
||||||
|
>
|
||||||
|
<el-select filterable v-model="role.ids" :placeholder="$t('organization.select_organization')" multiple>
|
||||||
|
<el-option
|
||||||
|
v-for="item in form.orgList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
<div v-if="role.id === 'test_manager'">
|
<div v-if="role.id === 'test_manager'">
|
||||||
<el-form-item :label="$t('workspace.select')"
|
<el-form-item :label="$t('workspace.select')"
|
||||||
:prop="'roles.' + index + '.ids'"
|
:prop="'roles.' + index + '.ids'"
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
size="mini"
|
size="mini"
|
||||||
:default-sort="{prop: 'num', order: 'ascending'}"
|
:default-sort="{prop: 'num', order: 'ascending'}"
|
||||||
highlight-current-row>
|
highlight-current-row>
|
||||||
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="15%"></el-table-column>
|
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="10%"></el-table-column>
|
||||||
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="35%">
|
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="35%">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<el-input
|
<el-input
|
||||||
|
@ -168,7 +168,7 @@
|
||||||
clearable/>
|
clearable/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('commons.input_content')" min-width="15%">
|
<el-table-column :label="$t('commons.input_content')" min-width="20%">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
:tip="$t('commons.search_by_name_or_id')"
|
:tip="$t('commons.search_by_name_or_id')"
|
||||||
:create-tip="$t('test_track.case.create')" @create="testCaseCreate">
|
:create-tip="$t('test_track.case.create')" @create="testCaseCreate">
|
||||||
<template v-slot:title>
|
<template v-slot:title>
|
||||||
<node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="refresh"/>
|
<node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="showAll"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:button>
|
<template v-slot:button>
|
||||||
<ms-table-button :is-tester-permission="true" icon="el-icon-download"
|
<ms-table-button :is-tester-permission="true" icon="el-icon-download"
|
||||||
|
@ -298,6 +298,9 @@ export default {
|
||||||
// param.nodeIds = this.selectNodeIds;
|
// param.nodeIds = this.selectNodeIds;
|
||||||
this.condition.nodeIds = this.selectNodeIds;
|
this.condition.nodeIds = this.selectNodeIds;
|
||||||
}
|
}
|
||||||
|
this.getData();
|
||||||
|
},
|
||||||
|
getData() {
|
||||||
if (this.currentProject) {
|
if (this.currentProject) {
|
||||||
this.condition.projectId = this.currentProject.id;
|
this.condition.projectId = this.currentProject.id;
|
||||||
this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
|
this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
|
||||||
|
@ -366,6 +369,10 @@ export default {
|
||||||
this.selectRows.clear();
|
this.selectRows.clear();
|
||||||
this.$emit('refresh');
|
this.$emit('refresh');
|
||||||
},
|
},
|
||||||
|
showAll() {
|
||||||
|
this.condition = {components: TEST_CASE_CONFIGS};
|
||||||
|
this.getData();
|
||||||
|
},
|
||||||
showDetail(row, event, column) {
|
showDetail(row, event, column) {
|
||||||
this.$emit('testCaseDetail', row);
|
this.$emit('testCaseDetail', row);
|
||||||
},
|
},
|
||||||
|
|
|
@ -106,6 +106,9 @@
|
||||||
nodeChange(nodeIds, pNodes) {
|
nodeChange(nodeIds, pNodes) {
|
||||||
this.selectNodeIds = nodeIds;
|
this.selectNodeIds = nodeIds;
|
||||||
this.selectParentNodes = pNodes;
|
this.selectParentNodes = pNodes;
|
||||||
|
// 切换node后,重置分页数
|
||||||
|
this.$refs.testPlanTestCaseList.currentPage = 1;
|
||||||
|
this.$refs.testPlanTestCaseList.pageSize = 10;
|
||||||
},
|
},
|
||||||
changePlan(plan) {
|
changePlan(plan) {
|
||||||
this.currentPlan = plan;
|
this.currentPlan = plan;
|
||||||
|
|
|
@ -93,6 +93,13 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="4" :offset="1" v-if="testCase.testId == 'other'">
|
||||||
|
<span class="cast_label">{{ $t('test_track.case.test_name') }}:</span>
|
||||||
|
<span class="cast_item">{{ testCase.otherTestName }}</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :offset="1">
|
<el-col :offset="1">
|
||||||
<span class="cast_label">{{ $t('test_track.case.prerequisite') }}:</span>
|
<span class="cast_label">{{ $t('test_track.case.prerequisite') }}:</span>
|
||||||
|
@ -100,7 +107,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row v-if="testCase.method === 'auto' && testCase.testId">
|
<el-row v-if="testCase.method === 'auto' && testCase.testId && testCase.testId != 'other'">
|
||||||
<el-col class="test-detail" :span="20" :offset="1">
|
<el-col class="test-detail" :span="20" :offset="1">
|
||||||
<el-tabs v-model="activeTab" type="border-card" @tab-click="testTabChange">
|
<el-tabs v-model="activeTab" type="border-card" @tab-click="testTabChange">
|
||||||
<el-tab-pane name="detail" :label="$t('test_track.plan_view.test_detail')">
|
<el-tab-pane name="detail" :label="$t('test_track.plan_view.test_detail')">
|
||||||
|
@ -220,7 +227,7 @@
|
||||||
<ckeditor :editor="editor" :disabled="isReadOnly" :config="editorConfig"
|
<ckeditor :editor="editor" :disabled="isReadOnly" :config="editorConfig"
|
||||||
v-model="testCase.issues.content"/>
|
v-model="testCase.issues.content"/>
|
||||||
<el-row v-if="hasTapdId">
|
<el-row v-if="hasTapdId">
|
||||||
{{ $t('test_track.issue.please_choose_current_owner') }}
|
{{ $t('test_track.issue.tapd_current_owner') }}
|
||||||
<el-select v-model="testCase.tapdUsers"
|
<el-select v-model="testCase.tapdUsers"
|
||||||
multiple
|
multiple
|
||||||
filterable
|
filterable
|
||||||
|
@ -231,6 +238,27 @@
|
||||||
:value="userInfo.user"/>
|
:value="userInfo.user"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-row v-if="hasZentaoId">
|
||||||
|
{{ $t('test_track.issue.zentao_bug_build') }}
|
||||||
|
<el-select v-model="testCase.zentaoBuilds"
|
||||||
|
multiple
|
||||||
|
filterable
|
||||||
|
style="width: 20%"
|
||||||
|
:placeholder="$t('test_track.issue.zentao_bug_build')"
|
||||||
|
collapse-tags size="small">
|
||||||
|
<el-option v-for="(build, index) in Builds" :key="index" :label="build.name"
|
||||||
|
:value="build.id"/>
|
||||||
|
</el-select>
|
||||||
|
{{ $t('test_track.issue.zentao_bug_assigned') }}
|
||||||
|
<el-select v-model="testCase.zentaoAssigned"
|
||||||
|
filterable
|
||||||
|
style="width: 20%"
|
||||||
|
:placeholder="$t('test_track.issue.please_choose_current_owner')"
|
||||||
|
collapse-tags size="small">
|
||||||
|
<el-option v-for="(userInfo, index) in zentaoUsers" :key="index" :label="userInfo.name"
|
||||||
|
:value="userInfo.user"/>
|
||||||
|
</el-select>
|
||||||
|
</el-row>
|
||||||
<el-button type="primary" size="small" @click="saveIssues">{{ $t('commons.save') }}</el-button>
|
<el-button type="primary" size="small" @click="saveIssues">{{ $t('commons.save') }}</el-button>
|
||||||
<el-button size="small" @click="issuesSwitch=false">{{ $t('commons.cancel') }}</el-button>
|
<el-button size="small" @click="issuesSwitch=false">{{ $t('commons.cancel') }}</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -360,7 +388,12 @@ export default {
|
||||||
activeTab: 'detail',
|
activeTab: 'detail',
|
||||||
isFailure: true,
|
isFailure: true,
|
||||||
users: [],
|
users: [],
|
||||||
|
Builds: [],
|
||||||
|
zentaoBuilds: [],
|
||||||
|
zentaoUsers: [],
|
||||||
|
zentaoAssigned: "",
|
||||||
hasTapdId: false,
|
hasTapdId: false,
|
||||||
|
hasZentaoId: false,
|
||||||
tableData: [],
|
tableData: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -481,6 +514,8 @@ export default {
|
||||||
this.showDialog = true;
|
this.showDialog = true;
|
||||||
this.issuesSwitch = false;
|
this.issuesSwitch = false;
|
||||||
this.activeTab = 'detail';
|
this.activeTab = 'detail';
|
||||||
|
this.hasTapdId = false;
|
||||||
|
this.hasZentaoId = false;
|
||||||
listenGoBack(this.handleClose);
|
listenGoBack(this.handleClose);
|
||||||
this.initData(testCase);
|
this.initData(testCase);
|
||||||
},
|
},
|
||||||
|
@ -558,6 +593,15 @@ export default {
|
||||||
this.users = response.data;
|
this.users = response.data;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (project.zentaoId) {
|
||||||
|
this.hasZentaoId = true;
|
||||||
|
this.result = this.$get("/issues/zentao/builds/" + this.testCase.caseId, response => {
|
||||||
|
this.Builds = response.data;
|
||||||
|
})
|
||||||
|
this.result = this.$get("/issues/zentao/user/" + this.testCase.caseId, response => {
|
||||||
|
this.zentaoUsers = response.data;
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -587,6 +631,8 @@ export default {
|
||||||
param.content = this.testCase.issues.content;
|
param.content = this.testCase.issues.content;
|
||||||
param.testCaseId = this.testCase.caseId;
|
param.testCaseId = this.testCase.caseId;
|
||||||
param.tapdUsers = this.testCase.tapdUsers;
|
param.tapdUsers = this.testCase.tapdUsers;
|
||||||
|
param.zentaoBuilds = this.testCase.zentaoBuilds;
|
||||||
|
param.zentaoUser = this.testCase.zentaoAssigned;
|
||||||
|
|
||||||
this.result = this.$post("/issues/add", param, () => {
|
this.result = this.$post("/issues/add", param, () => {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
|
@ -597,6 +643,8 @@ export default {
|
||||||
this.testCase.issues.title = "";
|
this.testCase.issues.title = "";
|
||||||
this.testCase.issues.content = "";
|
this.testCase.issues.content = "";
|
||||||
this.testCase.tapdUsers = [];
|
this.testCase.tapdUsers = [];
|
||||||
|
this.testCase.zentaoBuilds = [];
|
||||||
|
this.testCase.zentaoAssigned = "";
|
||||||
},
|
},
|
||||||
getIssues(caseId) {
|
getIssues(caseId) {
|
||||||
this.result = this.$get("/issues/get/" + caseId, response => {
|
this.result = this.$get("/issues/get/" + caseId, response => {
|
||||||
|
|
|
@ -210,14 +210,12 @@
|
||||||
let reset = this.exportReportReset;
|
let reset = this.exportReportReset;
|
||||||
|
|
||||||
this.$nextTick(function () {
|
this.$nextTick(function () {
|
||||||
setTimeout(() => {
|
|
||||||
html2canvas(document.getElementById('testCaseReportExport'), {
|
html2canvas(document.getElementById('testCaseReportExport'), {
|
||||||
scale: 2
|
// scale: 2
|
||||||
}).then(function(canvas) {
|
}).then(function(canvas) {
|
||||||
exportPdf(name, [canvas]);
|
exportPdf(name, [canvas]);
|
||||||
reset();
|
reset();
|
||||||
});
|
});
|
||||||
}, 1000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
|
@ -301,7 +301,7 @@ export default {
|
||||||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||||
},
|
},
|
||||||
handleEdit(testCase, index) {
|
handleEdit(testCase, index) {
|
||||||
console.log(testCase)
|
// console.log(testCase)
|
||||||
this.isReadOnly = false;
|
this.isReadOnly = false;
|
||||||
if (!checkoutTestManagerOrTestUser()) {
|
if (!checkoutTestManagerOrTestUser()) {
|
||||||
this.isReadOnly = true;
|
this.isReadOnly = true;
|
||||||
|
|
|
@ -26,14 +26,14 @@ body {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*解决高度塌陷和边距重叠*/
|
/* 解决高度塌陷和边距重叠 */
|
||||||
.clearfix:before, .clearfix:after {
|
.clearfix:before, .clearfix:after {
|
||||||
content: "";
|
content: "";
|
||||||
display: table;
|
display: table;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*解决富文本框中link显示问题*/
|
/* 解决富文本框中link显示问题 */
|
||||||
.ck-rounded-corners .ck.ck-balloon-panel, .ck.ck-balloon-panel.ck-rounded-corners {
|
.ck-rounded-corners .ck.ck-balloon-panel, .ck.ck-balloon-panel.ck-rounded-corners {
|
||||||
z-index: 10055 !important;
|
z-index: 10055 !important;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ body {
|
||||||
table-layout: fixed !important;
|
table-layout: fixed !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* <-- 表格拖拽表头调整宽度,在 t-bable 上添加 border 属性,并添加 adjust-table 类名*/
|
/* <-- 表格拖拽表头调整宽度,在 t-bable 上添加 border 属性,并添加 adjust-table 类名 */
|
||||||
.adjust-table td {
|
.adjust-table td {
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ body {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.adjust-table th:not([class*='el-table-column--selection']):hover:after {
|
.adjust-table th:not([class*="el-table-column--selection"]):hover:after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 25%;
|
top: 25%;
|
||||||
|
@ -81,7 +81,7 @@ body {
|
||||||
|
|
||||||
/* 表格拖拽表头调整宽度 --> */
|
/* 表格拖拽表头调整宽度 --> */
|
||||||
|
|
||||||
/* <-- 表格 input 编辑效果*/
|
/* <-- 表格 input 编辑效果 */
|
||||||
.table-edit-input .el-textarea__inner {
|
.table-edit-input .el-textarea__inner {
|
||||||
border-style: hidden;
|
border-style: hidden;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default {
|
||||||
operating: 'Operating',
|
operating: 'Operating',
|
||||||
input_limit: 'Within {0} and {1} characters',
|
input_limit: 'Within {0} and {1} characters',
|
||||||
login: 'Sign In',
|
login: 'Sign In',
|
||||||
welcome: 'Welcome back, please enter username and password to log in to MeterSphere',
|
welcome: 'Welcome back, please enter username and password to log in',
|
||||||
username: 'Username',
|
username: 'Username',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
input_username: 'Please enter username',
|
input_username: 'Please enter username',
|
||||||
|
@ -258,14 +258,14 @@ export default {
|
||||||
jira_issuetype: 'JIRA issuetype',
|
jira_issuetype: 'JIRA issuetype',
|
||||||
input_api_account: 'please enter account',
|
input_api_account: 'please enter account',
|
||||||
input_api_password: 'Please enter password',
|
input_api_password: 'Please enter password',
|
||||||
input_app_name: 'Please enter the application code',
|
|
||||||
input_app_key: 'Please enter the key',
|
|
||||||
input_jira_url: 'Please enter Jira address, for example: https://metersphere.atlassian.net/',
|
input_jira_url: 'Please enter Jira address, for example: https://metersphere.atlassian.net/',
|
||||||
input_jira_issuetype: 'Please enter the question type',
|
input_jira_issuetype: 'Please enter the question type',
|
||||||
|
zentao_url: 'Zentao url',
|
||||||
|
input_zentao_url: 'Please enter Zentao address, for example: http://xx.xx.xx.xx/zentao/',
|
||||||
use_tip: 'Usage guidelines:',
|
use_tip: 'Usage guidelines:',
|
||||||
use_tip_tapd: 'Basic Auth account information is queried in "Company Management-Security and Integration-Open Platform"',
|
use_tip_tapd: 'Basic Auth account information is queried in "Company Management-Security and Integration-Open Platform"',
|
||||||
use_tip_jira: 'Jira software server authentication information is account password, Jira software cloud authentication information is account + token (account settings-security-create API token)',
|
use_tip_jira: 'Jira software server authentication information is account password, Jira software cloud authentication information is account + token (account settings-security-create API token)',
|
||||||
use_tip_zentao: 'Log in to ZenTao as a super administrator user, enter the background-secondary development-application, click [Add Application] to add an application',
|
use_tip_zentao: 'The account password is a Zentao account with corresponding permissions, and the account needs to have super model calling interface permissions',
|
||||||
use_tip_two: 'After saving the Basic Auth account information, you need to manually associate the ID/key in the Metersphere project',
|
use_tip_two: 'After saving the Basic Auth account information, you need to manually associate the ID/key in the Metersphere project',
|
||||||
link_the_project_now: 'Link the project now',
|
link_the_project_now: 'Link the project now',
|
||||||
cancel_edit: 'Cancel edit',
|
cancel_edit: 'Cancel edit',
|
||||||
|
@ -292,6 +292,7 @@ export default {
|
||||||
special_characters_are_not_supported: 'Incorrect format (special characters are not supported and cannot end with \'-\')',
|
special_characters_are_not_supported: 'Incorrect format (special characters are not supported and cannot end with \'-\')',
|
||||||
tapd_id: 'TAPD Project ID',
|
tapd_id: 'TAPD Project ID',
|
||||||
jira_key: 'JIRA Project key',
|
jira_key: 'JIRA Project key',
|
||||||
|
zentao_id: 'Zentao Project ID',
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
create: 'Create',
|
create: 'Create',
|
||||||
|
@ -336,6 +337,7 @@ export default {
|
||||||
please_choose_role: 'Please Choose Role',
|
please_choose_role: 'Please Choose Role',
|
||||||
admin: 'Admin',
|
admin: 'Admin',
|
||||||
org_admin: 'Org_Admin',
|
org_admin: 'Org_Admin',
|
||||||
|
org_member: 'Org Member',
|
||||||
test_manager: 'Test Manager',
|
test_manager: 'Test Manager',
|
||||||
test_user: 'Test User',
|
test_user: 'Test User',
|
||||||
test_viewer: 'Read-only User',
|
test_viewer: 'Read-only User',
|
||||||
|
@ -360,6 +362,7 @@ export default {
|
||||||
test_stop_now_confirm: 'Are you sure you want to stop the current test immediately?',
|
test_stop_now_confirm: 'Are you sure you want to stop the current test immediately?',
|
||||||
test_rerun_confirm: 'Are you sure you want to rerun the current test immediately?',
|
test_rerun_confirm: 'Are you sure you want to rerun the current test immediately?',
|
||||||
test_stop_success: 'Test stop successfully',
|
test_stop_success: 'Test stop successfully',
|
||||||
|
downloadJtl: 'Download JTL',
|
||||||
test_execute_again: 'Test Execute Again',
|
test_execute_again: 'Test Execute Again',
|
||||||
export: 'Export',
|
export: 'Export',
|
||||||
compare: 'Compare',
|
compare: 'Compare',
|
||||||
|
@ -411,12 +414,12 @@ export default {
|
||||||
delete_file: "The file already exists, please delete the file with the same name first!",
|
delete_file: "The file already exists, please delete the file with the same name first!",
|
||||||
thread_num: 'Concurrent users:',
|
thread_num: 'Concurrent users:',
|
||||||
input_thread_num: 'Please enter the number of threads',
|
input_thread_num: 'Please enter the number of threads',
|
||||||
duration: 'Duration time (minutes):',
|
duration: 'Duration time (seconds):',
|
||||||
input_duration: 'Please enter a duration',
|
input_duration: 'Please enter a duration',
|
||||||
rps_limit: 'RPS Limit:',
|
rps_limit: 'RPS Limit:',
|
||||||
input_rps_limit: 'Please enter a limit',
|
input_rps_limit: 'Please enter a limit',
|
||||||
ramp_up_time_within: 'In',
|
ramp_up_time_within: 'In',
|
||||||
ramp_up_time_minutes: 'minutes, separate',
|
ramp_up_time_minutes: 'seconds, separate',
|
||||||
ramp_up_time_times: 'add concurrent users',
|
ramp_up_time_times: 'add concurrent users',
|
||||||
advanced_config_error: 'Advanced configuration verification failed',
|
advanced_config_error: 'Advanced configuration verification failed',
|
||||||
domain_bind: 'Domain bind',
|
domain_bind: 'Domain bind',
|
||||||
|
@ -748,7 +751,7 @@ export default {
|
||||||
detail: "Report detail",
|
detail: "Report detail",
|
||||||
delete: "Delete report",
|
delete: "Delete report",
|
||||||
batch_delete: "Delete reports in bulk",
|
batch_delete: "Delete reports in bulk",
|
||||||
running: "The test is running",
|
running: "The test is reporting",
|
||||||
not_exist: "Test report does not exist",
|
not_exist: "Test report does not exist",
|
||||||
},
|
},
|
||||||
test_track: {
|
test_track: {
|
||||||
|
@ -1016,6 +1019,8 @@ export default {
|
||||||
preview: "Preview",
|
preview: "Preview",
|
||||||
please_choose_current_owner: "Please choose current owner",
|
please_choose_current_owner: "Please choose current owner",
|
||||||
tapd_current_owner: "Tapd Current Owner:",
|
tapd_current_owner: "Tapd Current Owner:",
|
||||||
|
zentao_bug_build: "Zentao bug Impact version",
|
||||||
|
zentao_bug_assigned: "Zentao bug handler",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
test_resource_pool: {
|
test_resource_pool: {
|
||||||
|
@ -1148,7 +1153,7 @@ export default {
|
||||||
performance: "Number of performance tests",
|
performance: "Number of performance tests",
|
||||||
resource_pool: "Available test resource pool",
|
resource_pool: "Available test resource pool",
|
||||||
max_threads: "Maximum Concurrency",
|
max_threads: "Maximum Concurrency",
|
||||||
duration: "Stress test duration(minutes)",
|
duration: "Stress test duration(seconds)",
|
||||||
use_default: "Use default quota",
|
use_default: "Use default quota",
|
||||||
yes: "Yes",
|
yes: "Yes",
|
||||||
no: "No",
|
no: "No",
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default {
|
||||||
operating: '操作',
|
operating: '操作',
|
||||||
input_limit: '长度在 {0} 到 {1} 个字符',
|
input_limit: '长度在 {0} 到 {1} 个字符',
|
||||||
login: '登录',
|
login: '登录',
|
||||||
welcome: '欢迎回来,请输入用户名和密码登录MeterSphere',
|
welcome: '欢迎回来,请输入用户名和密码登录',
|
||||||
username: '姓名',
|
username: '姓名',
|
||||||
password: '密码',
|
password: '密码',
|
||||||
input_username: '请输入用户姓名',
|
input_username: '请输入用户姓名',
|
||||||
|
@ -257,15 +257,15 @@ export default {
|
||||||
jira_url: 'JIRA 地址',
|
jira_url: 'JIRA 地址',
|
||||||
jira_issuetype: '问题类型',
|
jira_issuetype: '问题类型',
|
||||||
input_api_account: '请输入账号',
|
input_api_account: '请输入账号',
|
||||||
input_api_password: '请输入口令',
|
input_api_password: '请输入密码',
|
||||||
input_app_name: '请输入应用代号',
|
|
||||||
input_app_key: '请输入密钥',
|
|
||||||
input_jira_url: '请输入Jira地址,例:https://metersphere.atlassian.net/',
|
input_jira_url: '请输入Jira地址,例:https://metersphere.atlassian.net/',
|
||||||
input_jira_issuetype: '请输入问题类型',
|
input_jira_issuetype: '请输入问题类型',
|
||||||
|
zentao_url: 'Zentao 地址',
|
||||||
|
input_zentao_url: '请输入Zentao地址,例:http://xx.xx.xx.xx/zentao/',
|
||||||
use_tip: '使用指引:',
|
use_tip: '使用指引:',
|
||||||
use_tip_tapd: 'Tapd Basic Auth 账号信息在"公司管理-安全与集成-开放平台"中查询',
|
use_tip_tapd: 'Tapd Basic Auth 账号信息在"公司管理-安全与集成-开放平台"中查询',
|
||||||
use_tip_jira: 'Jira software server 认证信息为 账号密码,Jira software cloud 认证信息为 账号+令牌(账户设置-安全-创建API令牌)',
|
use_tip_jira: 'Jira software server 认证信息为 账号密码,Jira software cloud 认证信息为 账号+令牌(账户设置-安全-创建API令牌)',
|
||||||
use_tip_zentao: '用超级管理员用户登录禅道,进入后台-二次开发-应用,点击【添加应用】新增一个应用',
|
use_tip_zentao: '账号密码为具有相应权限的Zentao账号,账号需要具有 超级model调用接口权限',
|
||||||
use_tip_two: '保存 Basic Auth 账号信息后,需要在 Metersphere 项目中手动关联 ID/key',
|
use_tip_two: '保存 Basic Auth 账号信息后,需要在 Metersphere 项目中手动关联 ID/key',
|
||||||
link_the_project_now: '马上关联项目',
|
link_the_project_now: '马上关联项目',
|
||||||
cancel_edit: '取消编辑',
|
cancel_edit: '取消编辑',
|
||||||
|
@ -291,6 +291,7 @@ export default {
|
||||||
special_characters_are_not_supported: '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)',
|
special_characters_are_not_supported: '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)',
|
||||||
tapd_id: 'TAPD项目ID',
|
tapd_id: 'TAPD项目ID',
|
||||||
jira_key: 'JIRA项目key',
|
jira_key: 'JIRA项目key',
|
||||||
|
zentao_id: 'Zentao项目ID',
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
create: '添加成员',
|
create: '添加成员',
|
||||||
|
@ -335,6 +336,7 @@ export default {
|
||||||
please_choose_role: '请选择角色',
|
please_choose_role: '请选择角色',
|
||||||
admin: '系统管理员',
|
admin: '系统管理员',
|
||||||
org_admin: '组织管理员',
|
org_admin: '组织管理员',
|
||||||
|
org_member: '组织成员',
|
||||||
test_manager: '测试经理',
|
test_manager: '测试经理',
|
||||||
test_user: '测试人员',
|
test_user: '测试人员',
|
||||||
test_viewer: '只读用户',
|
test_viewer: '只读用户',
|
||||||
|
@ -360,6 +362,7 @@ export default {
|
||||||
test_rerun_confirm: '确定要再次执行当前测试吗?',
|
test_rerun_confirm: '确定要再次执行当前测试吗?',
|
||||||
test_stop_success: '停止成功',
|
test_stop_success: '停止成功',
|
||||||
test_execute_again: '再次执行',
|
test_execute_again: '再次执行',
|
||||||
|
downloadJtl: '下载JTL',
|
||||||
export: '导出',
|
export: '导出',
|
||||||
compare: '比较',
|
compare: '比较',
|
||||||
generation_error: '报告生成错误, 无法查看, 请检查日志详情!',
|
generation_error: '报告生成错误, 无法查看, 请检查日志详情!',
|
||||||
|
@ -409,12 +412,12 @@ export default {
|
||||||
delete_file: "文件已存在,请先删除同名文件!",
|
delete_file: "文件已存在,请先删除同名文件!",
|
||||||
thread_num: '并发用户数:',
|
thread_num: '并发用户数:',
|
||||||
input_thread_num: '请输入线程数',
|
input_thread_num: '请输入线程数',
|
||||||
duration: '压测时长(分钟):',
|
duration: '压测时长(秒):',
|
||||||
input_duration: '请输入时长',
|
input_duration: '请输入时长',
|
||||||
rps_limit: 'RPS上限:',
|
rps_limit: 'RPS上限:',
|
||||||
input_rps_limit: '请输入限制',
|
input_rps_limit: '请输入限制',
|
||||||
ramp_up_time_within: '在',
|
ramp_up_time_within: '在',
|
||||||
ramp_up_time_minutes: '分钟内,分',
|
ramp_up_time_minutes: '秒内,分',
|
||||||
ramp_up_time_times: '次增加并发用户',
|
ramp_up_time_times: '次增加并发用户',
|
||||||
advanced_config_error: '高级配置校验失败',
|
advanced_config_error: '高级配置校验失败',
|
||||||
domain_bind: '域名绑定',
|
domain_bind: '域名绑定',
|
||||||
|
@ -752,7 +755,7 @@ export default {
|
||||||
detail: "报告详情",
|
detail: "报告详情",
|
||||||
delete: "删除报告",
|
delete: "删除报告",
|
||||||
batch_delete: "批量删除报告",
|
batch_delete: "批量删除报告",
|
||||||
running: "测试执行中",
|
running: "测试报告导出中",
|
||||||
not_exist: "测试报告不存在",
|
not_exist: "测试报告不存在",
|
||||||
},
|
},
|
||||||
test_track: {
|
test_track: {
|
||||||
|
@ -1019,7 +1022,9 @@ export default {
|
||||||
close_success: "关闭成功",
|
close_success: "关闭成功",
|
||||||
preview: "预览",
|
preview: "预览",
|
||||||
please_choose_current_owner: "请选择处理人",
|
please_choose_current_owner: "请选择处理人",
|
||||||
tapd_current_owner: "Tapd平台处理人:",
|
tapd_current_owner: "Tapd bug 处理人:",
|
||||||
|
zentao_bug_build: "禅道 bug 影响版本",
|
||||||
|
zentao_bug_assigned: "禅道 bug 处理人",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
test_resource_pool: {
|
test_resource_pool: {
|
||||||
|
@ -1151,7 +1156,7 @@ export default {
|
||||||
performance: "性能测试数量",
|
performance: "性能测试数量",
|
||||||
resource_pool: "可用测试资源池",
|
resource_pool: "可用测试资源池",
|
||||||
max_threads: "最大并发数",
|
max_threads: "最大并发数",
|
||||||
duration: "压测时长(分钟)",
|
duration: "压测时长(秒)",
|
||||||
use_default: "使用默认配额",
|
use_default: "使用默认配额",
|
||||||
yes: "是",
|
yes: "是",
|
||||||
no: "否",
|
no: "否",
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default {
|
||||||
operating: '操作',
|
operating: '操作',
|
||||||
input_limit: '長度在 {0} 到 {1} 個字符',
|
input_limit: '長度在 {0} 到 {1} 個字符',
|
||||||
login: '登錄',
|
login: '登錄',
|
||||||
welcome: '歡迎回來,請輸入用戶名和密碼登錄MeterSphere',
|
welcome: '歡迎回來,請輸入用戶名和密碼登錄',
|
||||||
username: '姓名',
|
username: '姓名',
|
||||||
password: '密碼',
|
password: '密碼',
|
||||||
input_username: '請輸入用戶姓名',
|
input_username: '請輸入用戶姓名',
|
||||||
|
@ -257,15 +257,15 @@ export default {
|
||||||
jira_url: 'JIRA 地址',
|
jira_url: 'JIRA 地址',
|
||||||
jira_issuetype: '問題類型',
|
jira_issuetype: '問題類型',
|
||||||
input_api_account: '請輸入賬號',
|
input_api_account: '請輸入賬號',
|
||||||
input_api_password: '請輸入口令',
|
input_api_password: '請輸入密碼',
|
||||||
input_app_name: '請輸入應用代號',
|
|
||||||
input_app_key: '請輸入密鑰',
|
|
||||||
input_jira_url: '請輸入Jira地址,例:https://metersphere.atlassian.net/',
|
input_jira_url: '請輸入Jira地址,例:https://metersphere.atlassian.net/',
|
||||||
input_jira_issuetype: '請輸入問題類型',
|
input_jira_issuetype: '請輸入問題類型',
|
||||||
|
zentao_url: 'Zentao 地址',
|
||||||
|
input_zentao_url: '請輸入Zentao地址,例:http://xx.xx.xx.xx/zentao/',
|
||||||
use_tip: '使用指引:',
|
use_tip: '使用指引:',
|
||||||
use_tip_tapd: 'Tapd Basic Auth 賬號信息在"公司管理-安全與集成-開放平臺"中查詢',
|
use_tip_tapd: 'Tapd Basic Auth 賬號信息在"公司管理-安全與集成-開放平臺"中查詢',
|
||||||
use_tip_jira: 'Jira software server 認證信息為 賬號密碼,Jira software cloud 認證信息為 賬號+令牌(賬戶設置-安全-創建API令牌)',
|
use_tip_jira: 'Jira software server 認證信息為 賬號密碼,Jira software cloud 認證信息為 賬號+令牌(賬戶設置-安全-創建API令牌)',
|
||||||
use_tip_zentao: '用超級管理員用戶登錄禪道,進入後台-二次開發-應用,點擊【添加應用】添加一個應用',
|
use_tip_zentao: '賬號密碼為具有相應權限的Zentao賬號,賬號需要具有 超級model調用接口權限',
|
||||||
use_tip_two: '保存 Basic Auth 賬號信息後,需要在 Metersphere 項目中手動關聯 ID/key',
|
use_tip_two: '保存 Basic Auth 賬號信息後,需要在 Metersphere 項目中手動關聯 ID/key',
|
||||||
link_the_project_now: '馬上關聯項目',
|
link_the_project_now: '馬上關聯項目',
|
||||||
cancel_edit: '取消編輯',
|
cancel_edit: '取消編輯',
|
||||||
|
@ -291,6 +291,7 @@ export default {
|
||||||
special_characters_are_not_supported: '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)',
|
special_characters_are_not_supported: '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)',
|
||||||
tapd_id: 'TAPD項目ID',
|
tapd_id: 'TAPD項目ID',
|
||||||
jira_key: 'JIRA項目key',
|
jira_key: 'JIRA項目key',
|
||||||
|
zentao_id: 'Zentao項目ID',
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
create: '添加成員',
|
create: '添加成員',
|
||||||
|
@ -335,6 +336,7 @@ export default {
|
||||||
please_choose_role: '請選擇角色',
|
please_choose_role: '請選擇角色',
|
||||||
admin: '系統管理員',
|
admin: '系統管理員',
|
||||||
org_admin: '組織管理員',
|
org_admin: '組織管理員',
|
||||||
|
org_member: '組織成員',
|
||||||
test_manager: '測試經理',
|
test_manager: '測試經理',
|
||||||
test_user: '測試人員',
|
test_user: '測試人員',
|
||||||
test_viewer: '只讀用戶',
|
test_viewer: '只讀用戶',
|
||||||
|
@ -358,6 +360,7 @@ export default {
|
||||||
test_stop_now: '立即停止',
|
test_stop_now: '立即停止',
|
||||||
test_stop_now_confirm: '確定要立即停止當前測試嗎?',
|
test_stop_now_confirm: '確定要立即停止當前測試嗎?',
|
||||||
test_rerun_confirm: '確定要再次執行當前測試嗎?',
|
test_rerun_confirm: '確定要再次執行當前測試嗎?',
|
||||||
|
downloadJtl: '下載JTL',
|
||||||
test_stop_success: '停止成功',
|
test_stop_success: '停止成功',
|
||||||
test_execute_again: '再次執行',
|
test_execute_again: '再次執行',
|
||||||
export: '導出',
|
export: '導出',
|
||||||
|
@ -409,12 +412,12 @@ export default {
|
||||||
delete_file: "文件已存在,請先刪除同名文件!",
|
delete_file: "文件已存在,請先刪除同名文件!",
|
||||||
thread_num: '並發用戶數:',
|
thread_num: '並發用戶數:',
|
||||||
input_thread_num: '請輸入線程數',
|
input_thread_num: '請輸入線程數',
|
||||||
duration: '壓測時長(分鐘):',
|
duration: '壓測時長(秒):',
|
||||||
input_duration: '請輸入時長',
|
input_duration: '請輸入時長',
|
||||||
rps_limit: 'RPS上限:',
|
rps_limit: 'RPS上限:',
|
||||||
input_rps_limit: '請輸入限制',
|
input_rps_limit: '請輸入限制',
|
||||||
ramp_up_time_within: '在',
|
ramp_up_time_within: '在',
|
||||||
ramp_up_time_minutes: '分鐘內,分',
|
ramp_up_time_minutes: '秒內,分',
|
||||||
ramp_up_time_times: '次增加並發用戶',
|
ramp_up_time_times: '次增加並發用戶',
|
||||||
advanced_config_error: '高級配置校驗失敗',
|
advanced_config_error: '高級配置校驗失敗',
|
||||||
domain_bind: '域名綁定',
|
domain_bind: '域名綁定',
|
||||||
|
@ -751,7 +754,7 @@ export default {
|
||||||
detail: "報告詳情",
|
detail: "報告詳情",
|
||||||
delete: "刪除報告",
|
delete: "刪除報告",
|
||||||
batch_delete: "批量刪除報告",
|
batch_delete: "批量刪除報告",
|
||||||
running: "測試執行中",
|
running: "測試報告導出中",
|
||||||
not_exist: "測試報告不存在",
|
not_exist: "測試報告不存在",
|
||||||
},
|
},
|
||||||
test_track: {
|
test_track: {
|
||||||
|
@ -1018,7 +1021,9 @@ export default {
|
||||||
close_success: "關閉成功",
|
close_success: "關閉成功",
|
||||||
preview: "預覽",
|
preview: "預覽",
|
||||||
please_choose_current_owner: "請選擇處理人",
|
please_choose_current_owner: "請選擇處理人",
|
||||||
tapd_current_owner: "Tapd平臺處理人:",
|
tapd_current_owner: "Tapd bug 處理人:",
|
||||||
|
zentao_bug_build: "禪道 bug 影響版本",
|
||||||
|
zentao_bug_assigned: "禪道 bug 處理人",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
test_resource_pool: {
|
test_resource_pool: {
|
||||||
|
|
Loading…
Reference in New Issue