Merge branch 'master' of https://github.com/metersphere/metersphere
# Conflicts: # frontend/src/business/components/track/review/view/components/TestReviewRelevance.vue
This commit is contained in:
commit
cbf2b89742
103
README.md
103
README.md
|
@ -76,7 +76,7 @@ v1.1.0 是 v1.0.0 之后的功能版本。
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="10">测试跟踪</td>
|
<td rowspan="17">测试跟踪</td>
|
||||||
<td>项目管理</td>
|
<td>项目管理</td>
|
||||||
<td>多项目支持,测试用例、测试计划与项目关联</td>
|
<td>多项目支持,测试用例、测试计划与项目关联</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -92,9 +92,22 @@ v1.1.0 是 v1.0.0 之后的功能版本。
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>快速导入用例到系统</td>
|
<td>快速导入用例到系统</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="4">测试用例评审</td>
|
||||||
|
<td>基于已有用例发起评审</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="5">测试计划跟踪</td>
|
<td>在线更新评审结果</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>支持多人在线添加评审评论</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>灵活的评审人分配形式</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="8">测试计划跟踪</td>
|
||||||
<td>基于已有用例发起测试计划</td>
|
<td>基于已有用例发起测试计划</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -110,8 +123,17 @@ v1.1.0 是 v1.0.0 之后的功能版本。
|
||||||
<td>与平台中的接口测试、性能测试功能结合,自动更新关联用例的结果</td>
|
<td>与平台中的接口测试、性能测试功能结合,自动更新关联用例的结果</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="7">接口测试</td>
|
<td>记录测试用例关联的缺陷</td>
|
||||||
<td rowspan="5">测试脚本</td>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>缺陷记录支持关联到 Jira/TAPD 平台</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>测试报告支持分享、导出</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="19">接口测试</td>
|
||||||
|
<td rowspan="12">测试脚本</td>
|
||||||
<td>在线编辑接口测试内容</td>
|
<td>在线编辑接口测试内容</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -123,19 +145,56 @@ v1.1.0 是 v1.0.0 之后的功能版本。
|
||||||
<tr>
|
<tr>
|
||||||
<td>支持多接口的场景化测试</td>
|
<td>支持多接口的场景化测试</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>测试场景复用</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>测试场景支持引用已有环境信息</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>测试环境信息管理</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>通过浏览器插件快速录制测试脚本</td>
|
<td>通过浏览器插件快速录制测试脚本</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2">测试报告</td>
|
<td>支持前后置 BeanShell/Python 脚本</td>
|
||||||
<td>测试执行后自动生成测试报告</td>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>上传并引用自定义 Jar 包</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>多协议支持,支持 HTTP、Dubbo、SQL、TCP 类型请求</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>支持等待时间、条件判断等逻辑控制功能</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="4">测试执行</td>
|
||||||
|
<td>内置定时任务支持</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>通过 Jenkins 插件触发测试执行</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>多个接口测试一键合并执行</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>一键创建性能测试</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3">测试报告</td>
|
||||||
|
<td>测试执行后自动生成动态实时测试报告</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>测试报告导出</td>
|
<td>测试报告导出</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="9">性能测试</td>
|
<td>通过邮件、IM 工具等通知执行结果</td>
|
||||||
<td rowspan="5">测试脚本</td>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="12">性能测试</td>
|
||||||
|
<td rowspan="6">测试脚本</td>
|
||||||
<td>完全兼容 JMeter 脚本</td>
|
<td>完全兼容 JMeter 脚本</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -150,6 +209,16 @@ v1.1.0 是 v1.0.0 之后的功能版本。
|
||||||
<tr>
|
<tr>
|
||||||
<td>通过浏览器插件快速录制测试脚本</td>
|
<td>通过浏览器插件快速录制测试脚本</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>多协议支持</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">测试执行</td>
|
||||||
|
<td>内置定时任务支持</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>通过 Jenkins 插件触发测试执行</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="4">测试报告</td>
|
<td rowspan="4">测试报告</td>
|
||||||
<td>测试执行后自动生成测试报告</td>
|
<td>测试执行后自动生成测试报告</td>
|
||||||
|
@ -164,27 +233,37 @@ v1.1.0 是 v1.0.0 之后的功能版本。
|
||||||
<td>查看测试日志详情</td>
|
<td>查看测试日志详情</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="6">系统管理</td>
|
<td rowspan="9">系统管理</td>
|
||||||
<td rowspan="2">租户管理</td>
|
<td rowspan="3">用户租户管理</td>
|
||||||
<td>支持多级租户体系</td>
|
<td>支持多级租户体系</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>支持多种租户角色</td>
|
<td>支持多种租户角色</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2">测试资源管理</td>
|
<td>LDAP 认证对接</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>测试资源管理</td>
|
||||||
<td>性能测试资源池管理</td>
|
<td>性能测试资源池管理</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">消息通知配置</td>
|
||||||
|
<td>IM 工具通知(如企业微信、钉钉)</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>邮件通知配置</td>
|
<td>邮件通知配置</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2">集成与扩展</td>
|
<td rowspan="3">集成与扩展</td>
|
||||||
<td>完善的 API 列表</td>
|
<td>完善的 API 列表</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>支持对接 Jenkins 等持续集成工具</td>
|
<td>支持对接 Jenkins 等持续集成工具</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>支持对接 Jira/TAPD 等缺陷管理工具</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package io.metersphere.api.controller;
|
||||||
|
|
||||||
|
import io.metersphere.api.dto.scenario.DatabaseConfig;
|
||||||
|
import io.metersphere.api.service.APIDatabaseService;
|
||||||
|
import io.metersphere.commons.constants.RoleConstants;
|
||||||
|
import org.apache.shiro.authz.annotation.Logical;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value = "/api/database")
|
||||||
|
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER}, logical = Logical.OR)
|
||||||
|
public class ApiDatabaseController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
APIDatabaseService apiDatabaseService;
|
||||||
|
|
||||||
|
@PostMapping("/validate")
|
||||||
|
public void validate(@RequestBody DatabaseConfig databaseConfig) {
|
||||||
|
apiDatabaseService.validate(databaseConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,4 +35,6 @@ public class HttpRequest extends Request {
|
||||||
private Long responseTimeout;
|
private Long responseTimeout;
|
||||||
@JSONField(ordinal = 16)
|
@JSONField(ordinal = 16)
|
||||||
private Boolean followRedirects;
|
private Boolean followRedirects;
|
||||||
|
@JSONField(ordinal = 17)
|
||||||
|
private Boolean doMultipartPost;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,12 @@ package io.metersphere.api.dto.scenario.request;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
@JSONType(typeName = RequestType.SQL)
|
@JSONType(typeName = RequestType.SQL)
|
||||||
|
@ -25,4 +28,6 @@ public class SqlRequest extends Request {
|
||||||
private String resultVariable;
|
private String resultVariable;
|
||||||
@JSONField(ordinal = 14)
|
@JSONField(ordinal = 14)
|
||||||
private String variableNames;
|
private String variableNames;
|
||||||
|
@JSONField(ordinal = 15)
|
||||||
|
private List<KeyValue> variables;
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
ResponseAssertionResult responseAssertionResult = new ResponseAssertionResult();
|
ResponseAssertionResult responseAssertionResult = new ResponseAssertionResult();
|
||||||
responseAssertionResult.setMessage(assertionResult.getFailureMessage());
|
responseAssertionResult.setMessage(assertionResult.getFailureMessage());
|
||||||
responseAssertionResult.setName(assertionResult.getName());
|
responseAssertionResult.setName(assertionResult.getName());
|
||||||
responseAssertionResult.setPass(!assertionResult.isFailure());
|
responseAssertionResult.setPass(!assertionResult.isFailure() && !assertionResult.isError());
|
||||||
return responseAssertionResult;
|
return responseAssertionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package io.metersphere.api.service;
|
||||||
|
|
||||||
|
import io.metersphere.api.dto.scenario.DatabaseConfig;
|
||||||
|
import io.metersphere.commons.exception.MSException;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class APIDatabaseService {
|
||||||
|
|
||||||
|
public void validate(DatabaseConfig databaseConfig) {
|
||||||
|
try {
|
||||||
|
DriverManager.getConnection(databaseConfig.getDbUrl(), databaseConfig.getUsername(), databaseConfig.getPassword());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
|
MSException.throwException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package io.metersphere.base.domain;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TestCaseFile implements Serializable {
|
||||||
|
private String caseId;
|
||||||
|
|
||||||
|
private String fileId;
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
|
@ -0,0 +1,340 @@
|
||||||
|
package io.metersphere.base.domain;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TestCaseFileExample {
|
||||||
|
protected String orderByClause;
|
||||||
|
|
||||||
|
protected boolean distinct;
|
||||||
|
|
||||||
|
protected List<Criteria> oredCriteria;
|
||||||
|
|
||||||
|
public TestCaseFileExample() {
|
||||||
|
oredCriteria = new ArrayList<Criteria>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderByClause(String orderByClause) {
|
||||||
|
this.orderByClause = orderByClause;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrderByClause() {
|
||||||
|
return orderByClause;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDistinct(boolean distinct) {
|
||||||
|
this.distinct = distinct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDistinct() {
|
||||||
|
return distinct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Criteria> getOredCriteria() {
|
||||||
|
return oredCriteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void or(Criteria criteria) {
|
||||||
|
oredCriteria.add(criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria or() {
|
||||||
|
Criteria criteria = createCriteriaInternal();
|
||||||
|
oredCriteria.add(criteria);
|
||||||
|
return criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria createCriteria() {
|
||||||
|
Criteria criteria = createCriteriaInternal();
|
||||||
|
if (oredCriteria.size() == 0) {
|
||||||
|
oredCriteria.add(criteria);
|
||||||
|
}
|
||||||
|
return criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Criteria createCriteriaInternal() {
|
||||||
|
Criteria criteria = new Criteria();
|
||||||
|
return criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
oredCriteria.clear();
|
||||||
|
orderByClause = null;
|
||||||
|
distinct = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract static class GeneratedCriteria {
|
||||||
|
protected List<Criterion> criteria;
|
||||||
|
|
||||||
|
protected GeneratedCriteria() {
|
||||||
|
super();
|
||||||
|
criteria = new ArrayList<Criterion>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return criteria.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Criterion> getAllCriteria() {
|
||||||
|
return criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Criterion> getCriteria() {
|
||||||
|
return criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addCriterion(String condition) {
|
||||||
|
if (condition == null) {
|
||||||
|
throw new RuntimeException("Value for condition cannot be null");
|
||||||
|
}
|
||||||
|
criteria.add(new Criterion(condition));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addCriterion(String condition, Object value, String property) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new RuntimeException("Value for " + property + " cannot be null");
|
||||||
|
}
|
||||||
|
criteria.add(new Criterion(condition, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addCriterion(String condition, Object value1, Object value2, String property) {
|
||||||
|
if (value1 == null || value2 == null) {
|
||||||
|
throw new RuntimeException("Between values for " + property + " cannot be null");
|
||||||
|
}
|
||||||
|
criteria.add(new Criterion(condition, value1, value2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdIsNull() {
|
||||||
|
addCriterion("case_id is null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdIsNotNull() {
|
||||||
|
addCriterion("case_id is not null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdEqualTo(String value) {
|
||||||
|
addCriterion("case_id =", value, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdNotEqualTo(String value) {
|
||||||
|
addCriterion("case_id <>", value, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdGreaterThan(String value) {
|
||||||
|
addCriterion("case_id >", value, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdGreaterThanOrEqualTo(String value) {
|
||||||
|
addCriterion("case_id >=", value, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdLessThan(String value) {
|
||||||
|
addCriterion("case_id <", value, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdLessThanOrEqualTo(String value) {
|
||||||
|
addCriterion("case_id <=", value, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdLike(String value) {
|
||||||
|
addCriterion("case_id like", value, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdNotLike(String value) {
|
||||||
|
addCriterion("case_id not like", value, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdIn(List<String> values) {
|
||||||
|
addCriterion("case_id in", values, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdNotIn(List<String> values) {
|
||||||
|
addCriterion("case_id not in", values, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdBetween(String value1, String value2) {
|
||||||
|
addCriterion("case_id between", value1, value2, "caseId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andCaseIdNotBetween(String value1, String value2) {
|
||||||
|
addCriterion("case_id not between", value1, value2, "caseId");
|
||||||
|
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 {
|
||||||
|
|
||||||
|
protected Criteria() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Criterion {
|
||||||
|
private String condition;
|
||||||
|
|
||||||
|
private Object value;
|
||||||
|
|
||||||
|
private Object secondValue;
|
||||||
|
|
||||||
|
private boolean noValue;
|
||||||
|
|
||||||
|
private boolean singleValue;
|
||||||
|
|
||||||
|
private boolean betweenValue;
|
||||||
|
|
||||||
|
private boolean listValue;
|
||||||
|
|
||||||
|
private String typeHandler;
|
||||||
|
|
||||||
|
public String getCondition() {
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getSecondValue() {
|
||||||
|
return secondValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNoValue() {
|
||||||
|
return noValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSingleValue() {
|
||||||
|
return singleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBetweenValue() {
|
||||||
|
return betweenValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isListValue() {
|
||||||
|
return listValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeHandler() {
|
||||||
|
return typeHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Criterion(String condition) {
|
||||||
|
super();
|
||||||
|
this.condition = condition;
|
||||||
|
this.typeHandler = null;
|
||||||
|
this.noValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Criterion(String condition, Object value, String typeHandler) {
|
||||||
|
super();
|
||||||
|
this.condition = condition;
|
||||||
|
this.value = value;
|
||||||
|
this.typeHandler = typeHandler;
|
||||||
|
if (value instanceof List<?>) {
|
||||||
|
this.listValue = true;
|
||||||
|
} else {
|
||||||
|
this.singleValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Criterion(String condition, Object value) {
|
||||||
|
this(condition, value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
|
||||||
|
super();
|
||||||
|
this.condition = condition;
|
||||||
|
this.value = value;
|
||||||
|
this.secondValue = secondValue;
|
||||||
|
this.typeHandler = typeHandler;
|
||||||
|
this.betweenValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Criterion(String condition, Object value, Object secondValue) {
|
||||||
|
this(condition, value, secondValue, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package io.metersphere.base.mapper;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.TestCaseFile;
|
||||||
|
import io.metersphere.base.domain.TestCaseFileExample;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
public interface TestCaseFileMapper {
|
||||||
|
long countByExample(TestCaseFileExample example);
|
||||||
|
|
||||||
|
int deleteByExample(TestCaseFileExample example);
|
||||||
|
|
||||||
|
int insert(TestCaseFile record);
|
||||||
|
|
||||||
|
int insertSelective(TestCaseFile record);
|
||||||
|
|
||||||
|
List<TestCaseFile> selectByExample(TestCaseFileExample example);
|
||||||
|
|
||||||
|
int updateByExampleSelective(@Param("record") TestCaseFile record, @Param("example") TestCaseFileExample example);
|
||||||
|
|
||||||
|
int updateByExample(@Param("record") TestCaseFile record, @Param("example") TestCaseFileExample example);
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="io.metersphere.base.mapper.TestCaseFileMapper">
|
||||||
|
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.TestCaseFile">
|
||||||
|
<result column="case_id" jdbcType="VARCHAR" property="caseId" />
|
||||||
|
<result column="file_id" jdbcType="VARCHAR" property="fileId" />
|
||||||
|
</resultMap>
|
||||||
|
<sql id="Example_Where_Clause">
|
||||||
|
<where>
|
||||||
|
<foreach collection="oredCriteria" item="criteria" separator="or">
|
||||||
|
<if test="criteria.valid">
|
||||||
|
<trim prefix="(" prefixOverrides="and" suffix=")">
|
||||||
|
<foreach collection="criteria.criteria" item="criterion">
|
||||||
|
<choose>
|
||||||
|
<when test="criterion.noValue">
|
||||||
|
and ${criterion.condition}
|
||||||
|
</when>
|
||||||
|
<when test="criterion.singleValue">
|
||||||
|
and ${criterion.condition} #{criterion.value}
|
||||||
|
</when>
|
||||||
|
<when test="criterion.betweenValue">
|
||||||
|
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
|
||||||
|
</when>
|
||||||
|
<when test="criterion.listValue">
|
||||||
|
and ${criterion.condition}
|
||||||
|
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
|
||||||
|
#{listItem}
|
||||||
|
</foreach>
|
||||||
|
</when>
|
||||||
|
</choose>
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
</if>
|
||||||
|
</foreach>
|
||||||
|
</where>
|
||||||
|
</sql>
|
||||||
|
<sql id="Update_By_Example_Where_Clause">
|
||||||
|
<where>
|
||||||
|
<foreach collection="example.oredCriteria" item="criteria" separator="or">
|
||||||
|
<if test="criteria.valid">
|
||||||
|
<trim prefix="(" prefixOverrides="and" suffix=")">
|
||||||
|
<foreach collection="criteria.criteria" item="criterion">
|
||||||
|
<choose>
|
||||||
|
<when test="criterion.noValue">
|
||||||
|
and ${criterion.condition}
|
||||||
|
</when>
|
||||||
|
<when test="criterion.singleValue">
|
||||||
|
and ${criterion.condition} #{criterion.value}
|
||||||
|
</when>
|
||||||
|
<when test="criterion.betweenValue">
|
||||||
|
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
|
||||||
|
</when>
|
||||||
|
<when test="criterion.listValue">
|
||||||
|
and ${criterion.condition}
|
||||||
|
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
|
||||||
|
#{listItem}
|
||||||
|
</foreach>
|
||||||
|
</when>
|
||||||
|
</choose>
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
</if>
|
||||||
|
</foreach>
|
||||||
|
</where>
|
||||||
|
</sql>
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
case_id, file_id
|
||||||
|
</sql>
|
||||||
|
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestCaseFileExample" resultMap="BaseResultMap">
|
||||||
|
select
|
||||||
|
<if test="distinct">
|
||||||
|
distinct
|
||||||
|
</if>
|
||||||
|
<include refid="Base_Column_List" />
|
||||||
|
from test_case_file
|
||||||
|
<if test="_parameter != null">
|
||||||
|
<include refid="Example_Where_Clause" />
|
||||||
|
</if>
|
||||||
|
<if test="orderByClause != null">
|
||||||
|
order by ${orderByClause}
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.TestCaseFileExample">
|
||||||
|
delete from test_case_file
|
||||||
|
<if test="_parameter != null">
|
||||||
|
<include refid="Example_Where_Clause" />
|
||||||
|
</if>
|
||||||
|
</delete>
|
||||||
|
<insert id="insert" parameterType="io.metersphere.base.domain.TestCaseFile">
|
||||||
|
insert into test_case_file (case_id, file_id)
|
||||||
|
values (#{caseId,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR})
|
||||||
|
</insert>
|
||||||
|
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseFile">
|
||||||
|
insert into test_case_file
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="caseId != null">
|
||||||
|
case_id,
|
||||||
|
</if>
|
||||||
|
<if test="fileId != null">
|
||||||
|
file_id,
|
||||||
|
</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="caseId != null">
|
||||||
|
#{caseId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="fileId != null">
|
||||||
|
#{fileId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
<select id="countByExample" parameterType="io.metersphere.base.domain.TestCaseFileExample" resultType="java.lang.Long">
|
||||||
|
select count(*) from test_case_file
|
||||||
|
<if test="_parameter != null">
|
||||||
|
<include refid="Example_Where_Clause" />
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
<update id="updateByExampleSelective" parameterType="map">
|
||||||
|
update test_case_file
|
||||||
|
<set>
|
||||||
|
<if test="record.caseId != null">
|
||||||
|
case_id = #{record.caseId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="record.fileId != null">
|
||||||
|
file_id = #{record.fileId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
</set>
|
||||||
|
<if test="_parameter != null">
|
||||||
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
|
</if>
|
||||||
|
</update>
|
||||||
|
<update id="updateByExample" parameterType="map">
|
||||||
|
update test_case_file
|
||||||
|
set case_id = #{record.caseId,jdbcType=VARCHAR},
|
||||||
|
file_id = #{record.fileId,jdbcType=VARCHAR}
|
||||||
|
<if test="_parameter != null">
|
||||||
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
|
</if>
|
||||||
|
</update>
|
||||||
|
</mapper>
|
|
@ -1,7 +1,7 @@
|
||||||
package io.metersphere.commons.constants;
|
package io.metersphere.commons.constants;
|
||||||
|
|
||||||
public enum FileType {
|
public enum FileType {
|
||||||
JMX(".jmx"), CSV(".csv"), JSON(".json");
|
JMX(".jmx"), CSV(".csv"), JSON(".json"), PDF(".pdf"), JPG(".jpg"), PNG(".png");
|
||||||
|
|
||||||
// 保存后缀
|
// 保存后缀
|
||||||
private String suffix;
|
private String suffix;
|
||||||
|
|
|
@ -25,6 +25,15 @@ public class TestController {
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/multipart", consumes = {"multipart/form-data"})
|
||||||
|
public Object testMultipart(@RequestPart(value = "id") String id, @RequestPart(value = "user") User user, @RequestParam(value = "name") String name) {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("id", id);
|
||||||
|
jsonObject.put("user", user.getName());
|
||||||
|
jsonObject.put("name", name);
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/{str}")
|
@GetMapping(value = "/{str}")
|
||||||
public Object getString(@PathVariable String str) throws InterruptedException {
|
public Object getString(@PathVariable String str) throws InterruptedException {
|
||||||
if (StringUtils.equals("error", str)) {
|
if (StringUtils.equals("error", str)) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.base.mapper.FileContentMapper;
|
import io.metersphere.base.mapper.FileContentMapper;
|
||||||
import io.metersphere.base.mapper.FileMetadataMapper;
|
import io.metersphere.base.mapper.FileMetadataMapper;
|
||||||
import io.metersphere.base.mapper.LoadTestFileMapper;
|
import io.metersphere.base.mapper.LoadTestFileMapper;
|
||||||
|
import io.metersphere.base.mapper.TestCaseFileMapper;
|
||||||
import io.metersphere.commons.constants.FileType;
|
import io.metersphere.commons.constants.FileType;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -24,6 +25,8 @@ public class FileService {
|
||||||
private LoadTestFileMapper loadTestFileMapper;
|
private LoadTestFileMapper loadTestFileMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private FileContentMapper fileContentMapper;
|
private FileContentMapper fileContentMapper;
|
||||||
|
@Resource
|
||||||
|
private TestCaseFileMapper testCaseFileMapper;
|
||||||
|
|
||||||
public byte[] loadFileAsBytes(String id) {
|
public byte[] loadFileAsBytes(String id) {
|
||||||
FileContent fileContent = fileContentMapper.selectByPrimaryKey(id);
|
FileContent fileContent = fileContentMapper.selectByPrimaryKey(id);
|
||||||
|
@ -66,6 +69,19 @@ public class FileService {
|
||||||
loadTestFileMapper.deleteByExample(example3);
|
loadTestFileMapper.deleteByExample(example3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteFileRelatedByIds(List<String> ids) {
|
||||||
|
if (CollectionUtils.isEmpty(ids)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FileMetadataExample example = new FileMetadataExample();
|
||||||
|
example.createCriteria().andIdIn(ids);
|
||||||
|
fileMetadataMapper.deleteByExample(example);
|
||||||
|
|
||||||
|
FileContentExample example2 = new FileContentExample();
|
||||||
|
example2.createCriteria().andFileIdIn(ids);
|
||||||
|
fileContentMapper.deleteByExample(example2);
|
||||||
|
}
|
||||||
|
|
||||||
public FileMetadata saveFile(MultipartFile file) {
|
public FileMetadata saveFile(MultipartFile file) {
|
||||||
final FileMetadata fileMetadata = new FileMetadata();
|
final FileMetadata fileMetadata = new FileMetadata();
|
||||||
fileMetadata.setId(UUID.randomUUID().toString());
|
fileMetadata.setId(UUID.randomUUID().toString());
|
||||||
|
@ -109,4 +125,19 @@ public class FileService {
|
||||||
String type = filename.substring(s);
|
String type = filename.substring(s);
|
||||||
return FileType.valueOf(type.toUpperCase());
|
return FileType.valueOf(type.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<FileMetadata> getFileMetadataByCaseId(String caseId) {
|
||||||
|
TestCaseFileExample testCaseFileExample = new TestCaseFileExample();
|
||||||
|
testCaseFileExample.createCriteria().andCaseIdEqualTo(caseId);
|
||||||
|
final List<TestCaseFile> testCaseFiles = testCaseFileMapper.selectByExample(testCaseFileExample);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(testCaseFiles)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> fileIds = testCaseFiles.stream().map(TestCaseFile::getFileId).collect(Collectors.toList());
|
||||||
|
FileMetadataExample example = new FileMetadataExample();
|
||||||
|
example.createCriteria().andIdIn(fileIds);
|
||||||
|
return fileMetadataMapper.selectByExample(example);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ package io.metersphere.track.controller;
|
||||||
|
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
|
import io.metersphere.base.domain.FileMetadata;
|
||||||
import io.metersphere.base.domain.Project;
|
import io.metersphere.base.domain.Project;
|
||||||
import io.metersphere.base.domain.TestCase;
|
import io.metersphere.base.domain.TestCase;
|
||||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||||
|
@ -11,12 +12,18 @@ import io.metersphere.commons.utils.Pager;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.excel.domain.ExcelResponse;
|
import io.metersphere.excel.domain.ExcelResponse;
|
||||||
import io.metersphere.service.CheckOwnerService;
|
import io.metersphere.service.CheckOwnerService;
|
||||||
|
import io.metersphere.service.FileService;
|
||||||
import io.metersphere.track.dto.TestCaseDTO;
|
import io.metersphere.track.dto.TestCaseDTO;
|
||||||
|
import io.metersphere.track.request.testcase.EditTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
||||||
|
import io.metersphere.track.request.testplan.FileOperationRequest;
|
||||||
import io.metersphere.track.service.TestCaseService;
|
import io.metersphere.track.service.TestCaseService;
|
||||||
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 org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@ -33,6 +40,8 @@ public class TestCaseController {
|
||||||
TestCaseService testCaseService;
|
TestCaseService testCaseService;
|
||||||
@Resource
|
@Resource
|
||||||
private CheckOwnerService checkOwnerService;
|
private CheckOwnerService checkOwnerService;
|
||||||
|
@Resource
|
||||||
|
private FileService fileService;
|
||||||
|
|
||||||
@PostMapping("/list/{goPage}/{pageSize}")
|
@PostMapping("/list/{goPage}/{pageSize}")
|
||||||
public Pager<List<TestCaseDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) {
|
public Pager<List<TestCaseDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) {
|
||||||
|
@ -96,16 +105,16 @@ public class TestCaseController {
|
||||||
return testCaseService.getProjectByTestCaseId(testCaseId);
|
return testCaseService.getProjectByTestCaseId(testCaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/add")
|
@PostMapping(value = "/add", consumes = {"multipart/form-data"})
|
||||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||||
public void addTestCase(@RequestBody TestCaseWithBLOBs testCase) {
|
public void addTestCase(@RequestPart("request") TestCaseWithBLOBs testCase, @RequestPart(value = "file") List<MultipartFile> files) {
|
||||||
testCaseService.addTestCase(testCase);
|
testCaseService.save(testCase, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/edit")
|
@PostMapping(value = "/edit", consumes = {"multipart/form-data"})
|
||||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||||
public void editTestCase(@RequestBody TestCaseWithBLOBs testCase) {
|
public void editTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file") List<MultipartFile> files) {
|
||||||
testCaseService.editTestCase(testCase);
|
testCaseService.edit(request, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/delete/{testCaseId}")
|
@PostMapping("/delete/{testCaseId}")
|
||||||
|
@ -152,4 +161,18 @@ public class TestCaseController {
|
||||||
testCaseService.deleteTestCaseBath(request);
|
testCaseService.deleteTestCaseBath(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/file/metadata/{caseId}")
|
||||||
|
public List<FileMetadata> getFileMetadata(@PathVariable String caseId) {
|
||||||
|
return fileService.getFileMetadataByCaseId(caseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/file/download")
|
||||||
|
public ResponseEntity<byte[]> downloadJmx(@RequestBody FileOperationRequest fileOperationRequest) {
|
||||||
|
byte[] bytes = fileService.loadFileAsBytes(fileOperationRequest.getId());
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileOperationRequest.getName() + "\"")
|
||||||
|
.body(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package io.metersphere.track.request.testcase;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.FileMetadata;
|
||||||
|
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EditTestCaseRequest extends TestCaseWithBLOBs {
|
||||||
|
private List<FileMetadata> updatedFileList;
|
||||||
|
}
|
|
@ -26,10 +26,13 @@ import io.metersphere.excel.listener.EasyExcelListener;
|
||||||
import io.metersphere.excel.listener.TestCaseDataListener;
|
import io.metersphere.excel.listener.TestCaseDataListener;
|
||||||
import io.metersphere.excel.utils.EasyExcelExporter;
|
import io.metersphere.excel.utils.EasyExcelExporter;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
|
import io.metersphere.service.FileService;
|
||||||
import io.metersphere.track.dto.TestCaseDTO;
|
import io.metersphere.track.dto.TestCaseDTO;
|
||||||
|
import io.metersphere.track.request.testcase.EditTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
||||||
import io.metersphere.xmind.XmindCaseParser;
|
import io.metersphere.xmind.XmindCaseParser;
|
||||||
|
import org.apache.commons.collections4.ListUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.ibatis.session.ExecutorType;
|
import org.apache.ibatis.session.ExecutorType;
|
||||||
import org.apache.ibatis.session.SqlSession;
|
import org.apache.ibatis.session.SqlSession;
|
||||||
|
@ -83,8 +86,12 @@ public class TestCaseService {
|
||||||
TestCaseReviewTestCaseMapper testCaseReviewTestCaseMapper;
|
TestCaseReviewTestCaseMapper testCaseReviewTestCaseMapper;
|
||||||
@Resource
|
@Resource
|
||||||
TestCaseCommentService testCaseCommentService;
|
TestCaseCommentService testCaseCommentService;
|
||||||
|
@Resource
|
||||||
|
FileService fileService;
|
||||||
|
@Resource
|
||||||
|
TestCaseFileMapper testCaseFileMapper;
|
||||||
|
|
||||||
public void addTestCase(TestCaseWithBLOBs testCase) {
|
private TestCaseWithBLOBs addTestCase(TestCaseWithBLOBs testCase) {
|
||||||
testCase.setName(testCase.getName());
|
testCase.setName(testCase.getName());
|
||||||
checkTestCaseExist(testCase);
|
checkTestCaseExist(testCase);
|
||||||
testCase.setId(UUID.randomUUID().toString());
|
testCase.setId(UUID.randomUUID().toString());
|
||||||
|
@ -93,6 +100,7 @@ public class TestCaseService {
|
||||||
testCase.setNum(getNextNum(testCase.getProjectId()));
|
testCase.setNum(getNextNum(testCase.getProjectId()));
|
||||||
testCase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
testCase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
||||||
testCaseMapper.insert(testCase);
|
testCaseMapper.insert(testCase);
|
||||||
|
return testCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TestCase> getTestCaseByNodeId(List<String> nodeIds) {
|
public List<TestCase> getTestCaseByNodeId(List<String> nodeIds) {
|
||||||
|
@ -574,4 +582,55 @@ public class TestCaseService {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String save(TestCaseWithBLOBs testCase, List<MultipartFile> files) {
|
||||||
|
if (files == null) {
|
||||||
|
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
||||||
|
}
|
||||||
|
final TestCaseWithBLOBs testCaseWithBLOBs = addTestCase(testCase);
|
||||||
|
files.forEach(file -> {
|
||||||
|
final FileMetadata fileMetadata = fileService.saveFile(file);
|
||||||
|
TestCaseFile testCaseFile = new TestCaseFile();
|
||||||
|
testCaseFile.setCaseId(testCaseWithBLOBs.getId());
|
||||||
|
testCaseFile.setFileId(fileMetadata.getId());
|
||||||
|
testCaseFileMapper.insert(testCaseFile);
|
||||||
|
});
|
||||||
|
return testCaseWithBLOBs.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String edit(EditTestCaseRequest request, List<MultipartFile> files) {
|
||||||
|
TestCaseWithBLOBs testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(request.getId());
|
||||||
|
if (testCaseWithBLOBs == null) {
|
||||||
|
MSException.throwException(Translator.get("edit_load_test_not_found") + request.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新选择了一个文件,删除原来的文件
|
||||||
|
List<FileMetadata> updatedFiles = request.getUpdatedFileList();
|
||||||
|
List<FileMetadata> originFiles = fileService.getFileMetadataByCaseId(request.getId());
|
||||||
|
List<String> updatedFileIds = updatedFiles.stream().map(FileMetadata::getId).collect(Collectors.toList());
|
||||||
|
List<String> originFileIds = originFiles.stream().map(FileMetadata::getId).collect(Collectors.toList());
|
||||||
|
// 相减
|
||||||
|
List<String> deleteFileIds = ListUtils.subtract(originFileIds, updatedFileIds);
|
||||||
|
fileService.deleteFileRelatedByIds(deleteFileIds);
|
||||||
|
|
||||||
|
if (!CollectionUtils.isEmpty(deleteFileIds)) {
|
||||||
|
TestCaseFileExample testCaseFileExample = new TestCaseFileExample();
|
||||||
|
testCaseFileExample.createCriteria().andFileIdIn(deleteFileIds);
|
||||||
|
testCaseFileMapper.deleteByExample(testCaseFileExample);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (files != null) {
|
||||||
|
files.forEach(file -> {
|
||||||
|
final FileMetadata fileMetadata = fileService.saveFile(file);
|
||||||
|
TestCaseFile testCaseFile = new TestCaseFile();
|
||||||
|
testCaseFile.setFileId(fileMetadata.getId());
|
||||||
|
testCaseFile.setCaseId(request.getId());
|
||||||
|
testCaseFileMapper.insert(testCaseFile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
editTestCase(request);
|
||||||
|
return request.getId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
create table if not exists test_case_file
|
||||||
|
(
|
||||||
|
case_id varchar(64) null,
|
||||||
|
file_id varchar(64) null,
|
||||||
|
constraint test_case_file_unique_key
|
||||||
|
unique (case_id, file_id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
@ -11,7 +11,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col>
|
<el-col>
|
||||||
<ms-api-variable-input :show-variable="showVariable" :is-read-only="isReadOnly" v-model="item.name" size="small" maxlength="200" @change="change"
|
<ms-api-variable-input :show-copy="showCopy" :show-variable="showVariable" :is-read-only="isReadOnly" v-model="item.name" size="small" maxlength="200" @change="change"
|
||||||
:placeholder="$t('api_test.variable_name')" show-word-limit/>
|
:placeholder="$t('api_test.variable_name')" show-word-limit/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col>
|
<el-col>
|
||||||
|
@ -45,6 +45,10 @@
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
showCopy: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<div class="variable-input">
|
<div class="variable-input">
|
||||||
<el-input class="el-input__inner_pd" :disabled="isReadOnly" :value="value" v-bind="$attrs" :size="size" @change="change" @input="input"/>
|
<el-input class="el-input__inner_pd" :disabled="isReadOnly" :value="value" v-bind="$attrs" :size="size" @change="change" @input="input"/>
|
||||||
<div :class="{'hidden': !showVariable}" class="variable-combine" v-if="value">
|
<div :class="{'hidden': !showVariable}" class="variable-combine" v-if="value">
|
||||||
<div class="variable">{{variable}}</div>
|
<div v-if="showCopy" class="variable">{{variable}}</div>
|
||||||
<el-tooltip :content="$t('api_test.copied')" manual v-model="visible" placement="top" :visible-arrow="false">
|
<el-tooltip v-if="showCopy" :content="$t('api_test.copied')" manual v-model="visible" placement="top" :visible-arrow="false">
|
||||||
<i class="el-icon-copy-document copy" @click="copy"/>
|
<i class="el-icon-copy-document copy" @click="copy"/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,6 +25,10 @@
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
showCopy: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
handleRemove(file) {
|
handleRemove(file) {
|
||||||
this.$refs.upload.handleRemove(file);
|
this.$refs.upload.handleRemove(file);
|
||||||
for (let i = 0; i < this.parameter.files.length; i++) {
|
for (let i = 0; i < this.parameter.files.length; i++) {
|
||||||
if (file.name === this.parameter.files[i].name) {
|
if (file.file.name === this.parameter.files[i].file.name) {
|
||||||
this.parameter.files.splice(i, 1);
|
this.parameter.files.splice(i, 1);
|
||||||
this.$refs.upload.handleRemove(file);
|
this.$refs.upload.handleRemove(file);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<el-form :model="commonConfig" :rules="rules" ref="commonConfig">
|
<el-form :model="commonConfig" :rules="rules" ref="commonConfig">
|
||||||
|
|
||||||
<span>{{$t('api_test.environment.globalVariable')}}</span>
|
<span>{{$t('api_test.environment.globalVariable')}}</span>
|
||||||
<ms-api-scenario-variables :items="commonConfig.variables"/>
|
<ms-api-scenario-variables :show-copy="false" :items="commonConfig.variables"/>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-switch v-model="commonConfig.enableHost" active-text="Hosts"/>
|
<el-switch v-model="commonConfig.enableHost" active-text="Hosts"/>
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
:active-text="$t('api_test.request.refer_to_environment')" @change="useEnvironmentChange">
|
:active-text="$t('api_test.request.refer_to_environment')" @change="useEnvironmentChange">
|
||||||
</el-switch>
|
</el-switch>
|
||||||
<el-checkbox class="follow-redirects-item" v-model="request.followRedirects">{{$t('api_test.request.follow_redirects')}}</el-checkbox>
|
<el-checkbox class="follow-redirects-item" v-model="request.followRedirects">{{$t('api_test.request.follow_redirects')}}</el-checkbox>
|
||||||
|
<el-checkbox class="do-multipart-post" v-model="request.doMultipartPost">{{$t('api_test.request.do_multipart_post')}}</el-checkbox>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small"
|
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small"
|
||||||
|
@ -200,31 +201,36 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.el-tag {
|
|
||||||
width: 100%;
|
|
||||||
height: 40px;
|
|
||||||
line-height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.environment-display {
|
.el-tag {
|
||||||
font-size: 14px;
|
width: 100%;
|
||||||
}
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.environment-name {
|
.environment-display {
|
||||||
font-weight: bold;
|
font-size: 14px;
|
||||||
font-style: italic;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.adjust-margin-bottom {
|
.environment-name {
|
||||||
margin-bottom: 10px;
|
font-weight: bold;
|
||||||
}
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.environment-url-tip {
|
.adjust-margin-bottom {
|
||||||
color: #F56C6C;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.follow-redirects-item {
|
.environment-url-tip {
|
||||||
margin-left: 30px;
|
color: #F56C6C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.follow-redirects-item {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.do-multipart-post {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<div class="request-type">
|
<div class="request-type">
|
||||||
{{ request.showType() }}
|
{{ request.showType() }}
|
||||||
</div>
|
</div>
|
||||||
<div class="request-method">
|
<div class="request-method" :style="{'color': getColor(request.enable, request.showMethod())}">
|
||||||
{{ request.showMethod() }}
|
{{ request.showMethod() }}
|
||||||
</div>
|
</div>
|
||||||
<div class="request-name">
|
<div class="request-name">
|
||||||
|
@ -85,7 +85,13 @@ export default {
|
||||||
selected: 0,
|
selected: 0,
|
||||||
visible: false,
|
visible: false,
|
||||||
types: RequestFactory.TYPES,
|
types: RequestFactory.TYPES,
|
||||||
type: ""
|
type: "",
|
||||||
|
methodColorMap: new Map([
|
||||||
|
['GET', "#61AFFE"], ['POST', '#49CC90'], ['PUT', '#fca130'],
|
||||||
|
['PATCH', '#E2EE11'], ['DELETE', '#f93e3d'], ['OPTIONS', '#0EF5DA'],
|
||||||
|
['HEAD', '#8E58E7'], ['CONNECT', '#90AFAE'],
|
||||||
|
['DUBBO', '#C36EEF'],['SQL', '#0AEAD4'],['TCP', '#0A52DF'],
|
||||||
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -156,6 +162,11 @@ export default {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getColor(enable, method) {
|
||||||
|
if (enable) {
|
||||||
|
return this.methodColorMap.get(method);
|
||||||
|
}
|
||||||
|
},
|
||||||
select(request) {
|
select(request) {
|
||||||
if (!request) {
|
if (!request) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -41,6 +41,10 @@
|
||||||
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small" type="primary" @click="runDebug">{{$t('api_test.request.debug')}}</el-button>
|
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small" type="primary" @click="runDebug">{{$t('api_test.request.debug')}}</el-button>
|
||||||
|
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
|
<el-tab-pane :label="$t('api_test.scenario.variables')" name="variables">
|
||||||
|
<ms-api-scenario-variables :is-read-only="isReadOnly" :items="request.variables"
|
||||||
|
:description="$t('api_test.scenario.kv_description')"/>
|
||||||
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.request.sql.sql_script')" name="sql">
|
<el-tab-pane :label="$t('api_test.request.sql.sql_script')" name="sql">
|
||||||
<div class="sql-content" >
|
<div class="sql-content" >
|
||||||
<ms-code-edit mode="sql" :read-only="isReadOnly" :modes="['sql']" :data.sync="request.query" theme="eclipse" ref="codeEdit"/>
|
<ms-code-edit mode="sql" :read-only="isReadOnly" :modes="['sql']" :data.sync="request.query" theme="eclipse" ref="codeEdit"/>
|
||||||
|
@ -74,10 +78,12 @@
|
||||||
import MsDubboConsumerService from "@/business/components/api/test/components/request/dubbo/ConsumerAndService";
|
import MsDubboConsumerService from "@/business/components/api/test/components/request/dubbo/ConsumerAndService";
|
||||||
import MsJsr233Processor from "../processor/Jsr233Processor";
|
import MsJsr233Processor from "../processor/Jsr233Processor";
|
||||||
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
|
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
|
||||||
|
import MsApiScenarioVariables from "../ApiScenarioVariables";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiSqlRequestForm",
|
name: "MsApiSqlRequestForm",
|
||||||
components: {
|
components: {
|
||||||
|
MsApiScenarioVariables,
|
||||||
MsCodeEdit,
|
MsCodeEdit,
|
||||||
MsJsr233Processor,
|
MsJsr233Processor,
|
||||||
MsDubboConsumerService,
|
MsDubboConsumerService,
|
||||||
|
@ -96,7 +102,7 @@
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeName: "sql",
|
activeName: "variables",
|
||||||
databaseConfigsOptions: [],
|
databaseConfigsOptions: [],
|
||||||
rules: {
|
rules: {
|
||||||
name: [
|
name: [
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
currentConfig: new DatabaseConfig()
|
currentConfig: new DatabaseConfig()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
configs() {
|
||||||
|
this.currentConfig = new DatabaseConfig();
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
saveConfig(config) {
|
saveConfig(config) {
|
||||||
for (let item of this.configs) {
|
for (let item of this.configs) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="database-from">
|
<div class="database-from" v-loading="result.loading">
|
||||||
<el-form :model="currentConfig" :rules="rules" label-width="150px" size="small" :disabled="isReadOnly" ref="databaseFrom">
|
<el-form :model="currentConfig" :rules="rules" label-width="150px" size="small" :disabled="isReadOnly" ref="databaseFrom">
|
||||||
|
|
||||||
<el-form-item :label="$t('api_test.request.sql.dataSource')" prop="name">
|
<el-form-item :label="$t('api_test.request.sql.dataSource')" prop="name">
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
<el-button type="primary" v-show="currentConfig.id" size="small" @click="validate()">{{$t('校验')}}</el-button>
|
||||||
<el-button type="primary" v-show="currentConfig.id" size="small" @click="save('update')">{{$t('commons.update')}}</el-button>
|
<el-button type="primary" v-show="currentConfig.id" size="small" @click="save('update')">{{$t('commons.update')}}</el-button>
|
||||||
<el-button type="primary" size="small" @click="save('add')">{{$t('commons.add')}}</el-button>
|
<el-button type="primary" size="small" @click="save('add')">{{$t('commons.add')}}</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -81,6 +82,7 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
drivers: DatabaseConfig.DRIVER_CLASS,
|
drivers: DatabaseConfig.DRIVER_CLASS,
|
||||||
|
result: {},
|
||||||
currentConfig: new DatabaseConfig(),
|
currentConfig: new DatabaseConfig(),
|
||||||
rules: {
|
rules: {
|
||||||
name: [
|
name: [
|
||||||
|
@ -124,6 +126,11 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
validate() {
|
||||||
|
this.result = this.$post('/api/database/validate', this.currentConfig, () => {
|
||||||
|
this.$success(this.$t('commons.connection_successful'));
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,6 +337,7 @@ export class HTTPSamplerProxy extends DefaultTestElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.boolProp("HTTPSampler.use_keepalive", options.keepalive, true);
|
this.boolProp("HTTPSampler.use_keepalive", options.keepalive, true);
|
||||||
|
this.boolProp("HTTPSampler.DO_MULTIPART_POST", options.doMultipartPost, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,6 +346,7 @@ export class HttpRequest extends Request {
|
||||||
this.environment = options.environment;
|
this.environment = options.environment;
|
||||||
this.useEnvironment = options.useEnvironment;
|
this.useEnvironment = options.useEnvironment;
|
||||||
this.debugReport = undefined;
|
this.debugReport = undefined;
|
||||||
|
this.doMultipartPost = options.doMultipartPost;
|
||||||
this.connectTimeout = options.connectTimeout || 60 * 1000;
|
this.connectTimeout = options.connectTimeout || 60 * 1000;
|
||||||
this.responseTimeout = options.responseTimeout;
|
this.responseTimeout = options.responseTimeout;
|
||||||
this.followRedirects = options.followRedirects === undefined ? true : options.followRedirects;
|
this.followRedirects = options.followRedirects === undefined ? true : options.followRedirects;
|
||||||
|
@ -476,13 +477,14 @@ export class SqlRequest extends Request {
|
||||||
this.useEnvironment = options.useEnvironment;
|
this.useEnvironment = options.useEnvironment;
|
||||||
this.resultVariable = options.resultVariable;
|
this.resultVariable = options.resultVariable;
|
||||||
this.variableNames = options.variableNames;
|
this.variableNames = options.variableNames;
|
||||||
|
this.variables = [];
|
||||||
this.debugReport = undefined;
|
this.debugReport = undefined;
|
||||||
this.dataSource = options.dataSource;
|
this.dataSource = options.dataSource;
|
||||||
this.query = options.query;
|
this.query = options.query;
|
||||||
// this.queryType = options.queryType;
|
// this.queryType = options.queryType;
|
||||||
this.queryTimeout = options.queryTimeout || 60000;
|
this.queryTimeout = options.queryTimeout || 60000;
|
||||||
|
|
||||||
this.sets({args: KeyValue, attachmentArgs: KeyValue}, options);
|
this.sets({args: KeyValue, attachmentArgs: KeyValue, variables: KeyValue}, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
isValid() {
|
||||||
|
@ -987,7 +989,7 @@ class JMXHttpRequest {
|
||||||
this.connectTimeout = request.connectTimeout;
|
this.connectTimeout = request.connectTimeout;
|
||||||
this.responseTimeout = request.responseTimeout;
|
this.responseTimeout = request.responseTimeout;
|
||||||
this.followRedirects = request.followRedirects;
|
this.followRedirects = request.followRedirects;
|
||||||
|
this.doMultipartPost = request.doMultipartPost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1115,7 +1117,6 @@ class JMXGenerator {
|
||||||
if (request.enable) {
|
if (request.enable) {
|
||||||
if (!request.isValid()) return;
|
if (!request.isValid()) return;
|
||||||
let sampler;
|
let sampler;
|
||||||
|
|
||||||
if (request instanceof DubboRequest) {
|
if (request instanceof DubboRequest) {
|
||||||
sampler = new DubboSample(request.name || "", new JMXDubboRequest(request, scenario.dubboConfig));
|
sampler = new DubboSample(request.name || "", new JMXDubboRequest(request, scenario.dubboConfig));
|
||||||
} else if (request instanceof HttpRequest) {
|
} else if (request instanceof HttpRequest) {
|
||||||
|
@ -1126,6 +1127,7 @@ class JMXGenerator {
|
||||||
} else if (request instanceof SqlRequest) {
|
} else if (request instanceof SqlRequest) {
|
||||||
request.dataSource = scenario.databaseConfigMap.get(request.dataSource);
|
request.dataSource = scenario.databaseConfigMap.get(request.dataSource);
|
||||||
sampler = new JDBCSampler(request.name || "", request);
|
sampler = new JDBCSampler(request.name || "", request);
|
||||||
|
this.addRequestVariables(sampler, request);
|
||||||
} else if (request instanceof TCPRequest) {
|
} else if (request instanceof TCPRequest) {
|
||||||
sampler = new TCPSampler(request.name || "", new JMXTCPRequest(request, scenario));
|
sampler = new TCPSampler(request.name || "", new JMXTCPRequest(request, scenario));
|
||||||
}
|
}
|
||||||
|
@ -1187,6 +1189,14 @@ class JMXGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addRequestVariables(httpSamplerProxy, request) {
|
||||||
|
let name = request.name + " Variables";
|
||||||
|
let variables = this.filterKV(request.variables);
|
||||||
|
if (variables && variables.length > 0) {
|
||||||
|
httpSamplerProxy.put(new Arguments(name, variables));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addScenarioCookieManager(threadGroup, scenario) {
|
addScenarioCookieManager(threadGroup, scenario) {
|
||||||
if (scenario.enableCookieShare) {
|
if (scenario.enableCookieShare) {
|
||||||
threadGroup.put(new CookieManager(scenario.name));
|
threadGroup.put(new CookieManager(scenario.name));
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<ms-tag v-if="value === 'Prepare'" type="info" :content="$t('test_track.case.status_prepare')"/>
|
||||||
|
<ms-tag v-if="value === 'Pass'" type="success" :content="$t('test_track.case.status_pass')"/>
|
||||||
|
<ms-tag v-if="value === 'UnPass'" type="danger" :content="$t('test_track.case.status_un_pass')"/>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsTag from "@/business/components/common/components/MsTag";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ReviewStatus",
|
||||||
|
components: {MsTag},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -209,6 +209,59 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<el-row style="margin-top: 15px;margin-bottom: 10px">
|
||||||
|
<el-col :offset="2" :span="20">附件:
|
||||||
|
<el-upload
|
||||||
|
action=""
|
||||||
|
:show-file-list="false"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:http-request="handleUpload"
|
||||||
|
:on-exceed="handleExceed"
|
||||||
|
multiple
|
||||||
|
:limit="3"
|
||||||
|
:file-list="fileList">
|
||||||
|
<el-button icon="el-icon-plus" size="mini"></el-button>
|
||||||
|
<!-- <span slot="tip" class="el-upload__tip"></span>-->
|
||||||
|
</el-upload>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row type="flex" justify="center">
|
||||||
|
<el-col :span="20">
|
||||||
|
<el-table class="basic-config" :data="tableData">
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
:label="$t('load_test.file_name')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="size"
|
||||||
|
:label="$t('load_test.file_size')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="type"
|
||||||
|
:label="$t('load_test.file_type')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('load_test.last_modify_time')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<i class="el-icon-time"/>
|
||||||
|
<span class="last-modified">{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('commons.operating')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<el-button @click="handleDownload(scope.row)" :disabled="!scope.row.id || readOnly" type="primary"
|
||||||
|
icon="el-icon-download"
|
||||||
|
size="mini" circle/>
|
||||||
|
<el-button :disabled="readOnly" @click="handleDelete(scope.row, scope.$index)" type="danger"
|
||||||
|
icon="el-icon-delete" size="mini"
|
||||||
|
circle/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
|
@ -234,6 +287,7 @@ import {TokenKey, WORKSPACE_ID} from '../../../../../common/js/constants';
|
||||||
import MsDialogFooter from '../../../common/components/MsDialogFooter'
|
import MsDialogFooter from '../../../common/components/MsDialogFooter'
|
||||||
import {listenGoBack, removeGoBackListener} from "../../../../../common/js/utils";
|
import {listenGoBack, removeGoBackListener} from "../../../../../common/js/utils";
|
||||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||||
|
import {Message} from "element-ui";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TestCaseEdit",
|
name: "TestCaseEdit",
|
||||||
|
@ -263,6 +317,9 @@ export default {
|
||||||
maintainerOptions: [],
|
maintainerOptions: [],
|
||||||
testOptions: [],
|
testOptions: [],
|
||||||
workspaceId: '',
|
workspaceId: '',
|
||||||
|
fileList: [],
|
||||||
|
tableData: [],
|
||||||
|
uploadList: [],
|
||||||
rules: {
|
rules: {
|
||||||
name: [
|
name: [
|
||||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||||
|
@ -339,6 +396,7 @@ export default {
|
||||||
tmp.steps = JSON.parse(testCase.steps);
|
tmp.steps = JSON.parse(testCase.steps);
|
||||||
Object.assign(this.form, tmp);
|
Object.assign(this.form, tmp);
|
||||||
this.form.module = testCase.nodeId;
|
this.form.module = testCase.nodeId;
|
||||||
|
this.getFileMetaData(testCase);
|
||||||
} else {
|
} else {
|
||||||
if (this.selectNode.data) {
|
if (this.selectNode.data) {
|
||||||
this.form.module = this.selectNode.data.id;
|
this.form.module = this.selectNode.data.id;
|
||||||
|
@ -358,6 +416,24 @@ export default {
|
||||||
this.reload();
|
this.reload();
|
||||||
this.dialogFormVisible = true;
|
this.dialogFormVisible = true;
|
||||||
},
|
},
|
||||||
|
getFileMetaData(testCase) {
|
||||||
|
this.fileList = [];
|
||||||
|
this.tableData = [];
|
||||||
|
this.uploadList = [];
|
||||||
|
this.result = this.$get("test/case/file/metadata/" + testCase.id, response => {
|
||||||
|
let files = response.data;
|
||||||
|
|
||||||
|
if (!files) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// deep copy
|
||||||
|
this.fileList = JSON.parse(JSON.stringify(files));
|
||||||
|
this.tableData = JSON.parse(JSON.stringify(files));
|
||||||
|
this.tableData.map(f => {
|
||||||
|
f.size = f.size + ' Bytes';
|
||||||
|
});
|
||||||
|
})
|
||||||
|
},
|
||||||
handleAddStep(index, data) {
|
handleAddStep(index, data) {
|
||||||
let step = {};
|
let step = {};
|
||||||
step.num = data.num + 1;
|
step.num = data.num + 1;
|
||||||
|
@ -400,7 +476,8 @@ export default {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
let param = this.buildParam();
|
let param = this.buildParam();
|
||||||
if (this.validate(param)) {
|
if (this.validate(param)) {
|
||||||
this.result = this.$post('/test/case/' + this.operationType, param, () => {
|
let option = this.getOption(param);
|
||||||
|
this.result = this.$request(option, () => {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
if (this.operationType == 'add' && this.isCreateContinue) {
|
if (this.operationType == 'add' && this.isCreateContinue) {
|
||||||
this.form.name = '';
|
this.form.name = '';
|
||||||
|
@ -411,6 +488,7 @@ export default {
|
||||||
result: ''
|
result: ''
|
||||||
}];
|
}];
|
||||||
this.form.remark = '';
|
this.form.remark = '';
|
||||||
|
this.form.uploadList = [];
|
||||||
this.$emit("refresh");
|
this.$emit("refresh");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -444,6 +522,32 @@ export default {
|
||||||
}
|
}
|
||||||
return param;
|
return param;
|
||||||
},
|
},
|
||||||
|
getOption(param) {
|
||||||
|
let formData = new FormData();
|
||||||
|
let url = '/test/case/' + this.operationType;
|
||||||
|
this.uploadList.forEach(f => {
|
||||||
|
formData.append("file", f);
|
||||||
|
});
|
||||||
|
|
||||||
|
param.updatedFileList = this.fileList;
|
||||||
|
|
||||||
|
let requestJson = JSON.stringify(param, function (key, value) {
|
||||||
|
return key === "file" ? undefined : value
|
||||||
|
});
|
||||||
|
|
||||||
|
formData.append('request', new Blob([requestJson], {
|
||||||
|
type: "application/json"
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
method: 'POST',
|
||||||
|
url: url,
|
||||||
|
data: formData,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
validate(param) {
|
validate(param) {
|
||||||
for (let i = 0; i < param.steps.length; i++) {
|
for (let i = 0; i < param.steps.length; i++) {
|
||||||
if ((param.steps[i].desc && param.steps[i].desc.length > 300) ||
|
if ((param.steps[i].desc && param.steps[i].desc.length > 300) ||
|
||||||
|
@ -527,7 +631,88 @@ export default {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
handleExceed() {
|
||||||
|
this.$error(this.$t('load_test.file_size_limit'));
|
||||||
|
},
|
||||||
|
beforeUpload(file) {
|
||||||
|
if (!this.fileValidator(file)) {
|
||||||
|
/// todo: 显示错误信息
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.tableData.filter(f => f.name === file.name).length > 0) {
|
||||||
|
this.$error(this.$t('load_test.delete_file'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = file.name.substring(file.name.lastIndexOf(".") + 1);
|
||||||
|
|
||||||
|
this.tableData.push({
|
||||||
|
name: file.name,
|
||||||
|
size: file.size + ' Bytes', /// todo: 按照大小显示Byte、KB、MB等
|
||||||
|
type: type.toUpperCase(),
|
||||||
|
updateTime: file.lastModified,
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
handleUpload(uploadResources) {
|
||||||
|
this.uploadList.push(uploadResources.file);
|
||||||
|
},
|
||||||
|
handleDownload(file) {
|
||||||
|
let data = {
|
||||||
|
name: file.name,
|
||||||
|
id: file.id,
|
||||||
|
};
|
||||||
|
let config = {
|
||||||
|
url: '/test/case/file/download',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
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 = file.name;
|
||||||
|
aTag.href = URL.createObjectURL(blob);
|
||||||
|
aTag.click();
|
||||||
|
URL.revokeObjectURL(aTag.href)
|
||||||
|
} else {
|
||||||
|
// IE10+下载
|
||||||
|
navigator.msSaveBlob(blob, this.filename)
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
Message.error({message: e.message, showClose: true});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDelete(file, index) {
|
||||||
|
this.$alert(this.$t('load_test.delete_file_confirm') + file.name + "?", '', {
|
||||||
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
|
callback: (action) => {
|
||||||
|
if (action === 'confirm') {
|
||||||
|
this._handleDelete(file, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_handleDelete(file, index) {
|
||||||
|
this.fileList.splice(index, 1);
|
||||||
|
this.tableData.splice(index, 1);
|
||||||
|
let i = this.uploadList.findIndex(upLoadFile => upLoadFile.name === file.name);
|
||||||
|
if (i > -1) {
|
||||||
|
this.uploadList.splice(i, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fileValidator(file) {
|
||||||
|
/// todo: 是否需要对文件内容和大小做限制
|
||||||
|
return file.size > 0;
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
>
|
>
|
||||||
<test-case-detail :test-case="scope.row"/>
|
<test-case-detail :test-case="scope.row"/>
|
||||||
<p slot="reference">{{ scope.row.name }}</p>
|
<span slot="reference">{{ scope.row.name }}</span>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -107,7 +107,7 @@
|
||||||
:label="$t('test_track.case.status')">
|
:label="$t('test_track.case.status')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
<status-table-item :value="scope.row.reviewStatus"/>
|
<review-status :value="scope.row.reviewStatus"/>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -174,6 +174,7 @@
|
||||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||||
import StatusTableItem from "@/business/components/track/common/tableItems/planview/StatusTableItem";
|
import StatusTableItem from "@/business/components/track/common/tableItems/planview/StatusTableItem";
|
||||||
import TestCaseDetail from "./TestCaseDetail";
|
import TestCaseDetail from "./TestCaseDetail";
|
||||||
|
import ReviewStatus from "@/business/components/track/case/components/ReviewStatus";
|
||||||
export default {
|
export default {
|
||||||
name: "TestCaseList",
|
name: "TestCaseList",
|
||||||
components: {
|
components: {
|
||||||
|
@ -192,7 +193,8 @@
|
||||||
ShowMoreBtn,
|
ShowMoreBtn,
|
||||||
BatchEdit,
|
BatchEdit,
|
||||||
StatusTableItem,
|
StatusTableItem,
|
||||||
TestCaseDetail
|
TestCaseDetail,
|
||||||
|
ReviewStatus
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -222,9 +224,9 @@
|
||||||
{text: this.$t('commons.api'), value: 'api'}
|
{text: this.$t('commons.api'), value: 'api'}
|
||||||
],
|
],
|
||||||
statusFilters: [
|
statusFilters: [
|
||||||
{text: this.$t('test_track.plan.plan_status_prepare'), value: 'Prepare'},
|
{text: this.$t('test_track.case.status_prepare'), value: 'Prepare'},
|
||||||
{text: this.$t('test_track.plan_view.pass'), value: 'Pass'},
|
{text: this.$t('test_track.case.status_pass'), value: 'Pass'},
|
||||||
{text: '未通过', value: 'UnPass'},
|
{text: this.$t('test_track.case.status_un_pass'), value: 'UnPass'},
|
||||||
],
|
],
|
||||||
showMore: false,
|
showMore: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
|
|
|
@ -347,11 +347,7 @@ export default {
|
||||||
});
|
});
|
||||||
this.refreshTableAndPlan();
|
this.refreshTableAndPlan();
|
||||||
this.isTestManagerOrTestUser = checkoutTestManagerOrTestUser();
|
this.isTestManagerOrTestUser = checkoutTestManagerOrTestUser();
|
||||||
this.result = this.$get('user/list', response => {
|
this.getMaintainerOptions();
|
||||||
this.executorFilters = response.data.map(u => {
|
|
||||||
return {text: u.name, value: u.id}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
hub.$off("openFailureTestCase");
|
hub.$off("openFailureTestCase");
|
||||||
|
@ -583,6 +579,9 @@ export default {
|
||||||
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
||||||
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
|
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
|
||||||
this.valueArr.executor = response.data;
|
this.valueArr.executor = response.data;
|
||||||
|
this.executorFilters = response.data.map(u => {
|
||||||
|
return {text: u.name, value: u.id}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
:label="$t('test_track.review_view.execute_result')">
|
:label="$t('test_track.review_view.execute_result')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
<status-table-item :value="scope.row.reviewStatus"/>
|
<review-status :value="scope.row.reviewStatus"/>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -169,6 +169,7 @@ import {_filter, _sort, checkoutTestManagerOrTestUser, hasRoles} from "../../../
|
||||||
import {TEST_CASE_CONFIGS} from "../../../../common/components/search/search-components";
|
import {TEST_CASE_CONFIGS} from "../../../../common/components/search/search-components";
|
||||||
import {ROLE_TEST_MANAGER, ROLE_TEST_USER} from "../../../../../../common/js/constants";
|
import {ROLE_TEST_MANAGER, ROLE_TEST_USER} from "../../../../../../common/js/constants";
|
||||||
import TestReviewTestCaseEdit from "./TestReviewTestCaseEdit";
|
import TestReviewTestCaseEdit from "./TestReviewTestCaseEdit";
|
||||||
|
import ReviewStatus from "@/business/components/track/case/components/ReviewStatus";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TestReviewTestCaseList",
|
name: "TestReviewTestCaseList",
|
||||||
|
@ -176,7 +177,7 @@ export default {
|
||||||
MsTableOperatorButton, MsTableOperator, MethodTableItem, TypeTableItem,
|
MsTableOperatorButton, MsTableOperator, MethodTableItem, TypeTableItem,
|
||||||
StatusTableItem, PriorityTableItem, StatusEdit,
|
StatusTableItem, PriorityTableItem, StatusEdit,
|
||||||
ExecutorEdit, MsTipButton, TestReviewTestCaseEdit, MsTableHeader,
|
ExecutorEdit, MsTipButton, TestReviewTestCaseEdit, MsTableHeader,
|
||||||
NodeBreadcrumb, MsTableButton, ShowMoreBtn, BatchEdit, MsTablePagination
|
NodeBreadcrumb, MsTableButton, ShowMoreBtn, BatchEdit, MsTablePagination, ReviewStatus
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -504,6 +504,7 @@ export default {
|
||||||
connect_timeout: "Connect Timeout",
|
connect_timeout: "Connect Timeout",
|
||||||
response_timeout: "Response Timeout",
|
response_timeout: "Response Timeout",
|
||||||
follow_redirects: "Follow Redirects",
|
follow_redirects: "Follow Redirects",
|
||||||
|
do_multipart_post: "Use multipart/form-data for POST",
|
||||||
body_upload_limit_size: "The file size does not exceed 500 MB",
|
body_upload_limit_size: "The file size does not exceed 500 MB",
|
||||||
condition: "condition",
|
condition: "condition",
|
||||||
condition_variable: "Variable, e.g: ${var}",
|
condition_variable: "Variable, e.g: ${var}",
|
||||||
|
@ -713,8 +714,8 @@ export default {
|
||||||
batch_delete_case: 'Batch delete',
|
batch_delete_case: 'Batch delete',
|
||||||
batch_unlink: 'Batch Unlink',
|
batch_unlink: 'Batch Unlink',
|
||||||
project_name: "Project",
|
project_name: "Project",
|
||||||
status: 'Status',
|
status: 'Review Status',
|
||||||
status_prepare: 'Prepare',
|
status_prepare: 'Not reviewed',
|
||||||
status_pass: 'Pass',
|
status_pass: 'Pass',
|
||||||
status_un_pass: 'UnPass',
|
status_un_pass: 'UnPass',
|
||||||
cancel_relevance_project: "Disassociating the project will also cancel the associated test cases under the project",
|
cancel_relevance_project: "Disassociating the project will also cancel the associated test cases under the project",
|
||||||
|
|
|
@ -505,6 +505,7 @@ export default {
|
||||||
connect_timeout: "连接超时",
|
connect_timeout: "连接超时",
|
||||||
response_timeout: "响应超时",
|
response_timeout: "响应超时",
|
||||||
follow_redirects: "跟随重定向",
|
follow_redirects: "跟随重定向",
|
||||||
|
do_multipart_post: "对 POST 使用 multipart/form-data",
|
||||||
body_upload_limit_size: "上传文件大小不能超过 500 MB!",
|
body_upload_limit_size: "上传文件大小不能超过 500 MB!",
|
||||||
condition: "条件",
|
condition: "条件",
|
||||||
condition_variable: "变量,例如: ${var}",
|
condition_variable: "变量,例如: ${var}",
|
||||||
|
@ -715,8 +716,8 @@ export default {
|
||||||
batch_delete_case: '批量删除用例',
|
batch_delete_case: '批量删除用例',
|
||||||
batch_unlink: '批量取消关联',
|
batch_unlink: '批量取消关联',
|
||||||
project_name: '所属项目',
|
project_name: '所属项目',
|
||||||
status: '状态',
|
status: '评审状态',
|
||||||
status_prepare: '未开始',
|
status_prepare: '未评审',
|
||||||
status_pass: '通过',
|
status_pass: '通过',
|
||||||
status_un_pass: '未通过',
|
status_un_pass: '未通过',
|
||||||
cancel_relevance_project: "取消项目关联会同时取消该项目下已关联的测试用例",
|
cancel_relevance_project: "取消项目关联会同时取消该项目下已关联的测试用例",
|
||||||
|
|
|
@ -505,6 +505,7 @@ export default {
|
||||||
connect_timeout: "連接超時",
|
connect_timeout: "連接超時",
|
||||||
response_timeout: "響應超時",
|
response_timeout: "響應超時",
|
||||||
follow_redirects: "跟隨重定向",
|
follow_redirects: "跟隨重定向",
|
||||||
|
do_multipart_post: "對 POST 使用 multipart/form-data",
|
||||||
body_upload_limit_size: "上傳文件大小不能超過 500 MB!",
|
body_upload_limit_size: "上傳文件大小不能超過 500 MB!",
|
||||||
condition: "條件",
|
condition: "條件",
|
||||||
condition_variable: "變量,例如: ${var}",
|
condition_variable: "變量,例如: ${var}",
|
||||||
|
@ -715,8 +716,8 @@ export default {
|
||||||
batch_delete_case: '批量刪除用例',
|
batch_delete_case: '批量刪除用例',
|
||||||
batch_unlink: '批量取消關聯',
|
batch_unlink: '批量取消關聯',
|
||||||
project_name: '所屬項目',
|
project_name: '所屬項目',
|
||||||
status: '狀態',
|
status: '評審狀態',
|
||||||
status_prepare: '未開始',
|
status_prepare: '未評審',
|
||||||
status_pass: '通過',
|
status_pass: '通過',
|
||||||
status_un_pass: '未通過',
|
status_un_pass: '未通過',
|
||||||
cancel_relevance_project: "取消項目關聯會同時取消該項目下已關聯的測試用例",
|
cancel_relevance_project: "取消項目關聯會同時取消該項目下已關聯的測試用例",
|
||||||
|
|
Loading…
Reference in New Issue