Merge remote-tracking branch 'origin/master' into master

This commit is contained in:
Captain.B 2021-03-20 13:21:59 +08:00
commit 6f618c2cdf
58 changed files with 396 additions and 160 deletions

View File

@ -73,6 +73,10 @@ public class MsScenario extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) { if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
return; return;
} else if (this.getReferenced() != null && this.getReferenced().equals("REF")) { } else if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
@ -198,6 +202,8 @@ public class MsScenario extends MsTestElement {
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
); );
// 清空变量防止重复添加
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().clear();
} }
if (arguments.getArguments() != null && arguments.getArguments().size() > 0) { if (arguments.getArguments() != null && arguments.getArguments().size() > 0) {
return arguments; return arguments;

View File

@ -27,6 +27,10 @@ public class MsAssertions extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
addAssertions(tree); addAssertions(tree);
} }

View File

@ -26,6 +26,10 @@ public class MsIfController extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
final HashTree groupTree = tree.add(ifController()); final HashTree groupTree = tree.add(ifController());
if (CollectionUtils.isNotEmpty(hashTree)) { if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> { hashTree.forEach(el -> {

View File

@ -44,6 +44,10 @@ public class MsLoopController extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
final HashTree groupTree = controller(tree); final HashTree groupTree = controller(tree);
if (CollectionUtils.isNotEmpty(config.getVariables())) { if (CollectionUtils.isNotEmpty(config.getVariables())) {
this.addCsvDataSet(groupTree, config.getVariables()); this.addCsvDataSet(groupTree, config.getVariables());

View File

@ -26,7 +26,8 @@ public class MsDNSCacheManager extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) { // 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return; return;
} }
for (MsTestElement el : hashTree) { for (MsTestElement el : hashTree) {

View File

@ -30,6 +30,10 @@ public class MsExtract extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
addRequestExtractors(tree); addRequestExtractors(tree);
} }

View File

@ -29,6 +29,10 @@ public class MsJSR223Processor extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
JSR223Sampler processor = new JSR223Sampler(); JSR223Sampler processor = new JSR223Sampler();
processor.setEnabled(this.isEnable()); processor.setEnabled(this.isEnable());
if (StringUtils.isNotEmpty(this.getName())) { if (StringUtils.isNotEmpty(this.getName())) {

View File

@ -29,6 +29,10 @@ public class MsJSR223PostProcessor extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
JSR223PostProcessor processor = new JSR223PostProcessor(); JSR223PostProcessor processor = new JSR223PostProcessor();
processor.setEnabled(this.isEnable()); processor.setEnabled(this.isEnable());
if (StringUtils.isNotEmpty(this.getName())) { if (StringUtils.isNotEmpty(this.getName())) {

View File

@ -30,6 +30,10 @@ public class MsJSR223PreProcessor extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
final HashTree jsr223PreTree = tree.add(getJSR223PreProcessor()); final HashTree jsr223PreTree = tree.add(getJSR223PreProcessor());
if (CollectionUtils.isNotEmpty(hashTree)) { if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> { hashTree.forEach(el -> {

View File

@ -60,6 +60,10 @@ public class MsDubboSampler extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
if (this.getReferenced() != null && "Deleted".equals(this.getReferenced())) { if (this.getReferenced() != null && "Deleted".equals(this.getReferenced())) {
return; return;
} }

View File

@ -93,7 +93,10 @@ public class MsHTTPSamplerProxy extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) { if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) {
this.getRefElement(this); this.getRefElement(this);
} }
@ -315,7 +318,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
headerManager.add(new Header(keyValue.getName(), keyValue.getValue())) headerManager.add(new Header(keyValue.getName(), keyValue.getValue()))
); );
tree.add(headerManager); if (headerManager.getHeaders().size() > 0) {
tree.add(headerManager);
}
} }
public boolean isURL(String str) { public boolean isURL(String str) {

View File

@ -58,6 +58,10 @@ public class MsJDBCSampler extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) { if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) {
this.getRefElement(this); this.getRefElement(this);
} }

View File

@ -72,6 +72,10 @@ public class MsTCPSampler extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) { if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) {
this.getRefElement(this); this.getRefElement(this);
} }

View File

@ -26,7 +26,10 @@ public class MsConstantTimer extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
final HashTree groupTree = tree.add(constantTimer()); final HashTree groupTree = tree.add(constantTimer());
if (CollectionUtils.isNotEmpty(hashTree)) { if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> { hashTree.forEach(el -> {

View File

@ -3,6 +3,7 @@ package io.metersphere.api.dto.definition.request.unknown;
import com.alibaba.fastjson.annotation.JSONType; import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement; import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig; import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.commons.utils.LogUtil;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -31,22 +32,31 @@ public class MsJmeterElement extends MsTestElement {
@Override @Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) { public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
try { try {
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
InputStream inputSource = getStrToStream(jmeterElement); InputStream inputSource = getStrToStream(jmeterElement);
if (inputSource != null) { if (inputSource != null) {
Object scriptWrapper = SaveService.loadElement(inputSource); Object scriptWrapper = SaveService.loadElement(inputSource);
HashTree elementTree = tree; HashTree elementTree = tree;
this.setElementType(scriptWrapper.getClass().getName()); this.setElementType(scriptWrapper.getClass().getName());
if (scriptWrapper instanceof TestElement) {
((TestElement) scriptWrapper).setName(this.getName());
((TestElement) scriptWrapper).setEnabled(this.isEnable());
}
if (config.isOperating()) { if (config.isOperating()) {
elementTree = tree.add(scriptWrapper); elementTree = tree.add(scriptWrapper);
} else if (!(scriptWrapper instanceof TestPlan) && !(scriptWrapper instanceof ThreadGroup)) { } else if (!(scriptWrapper instanceof TestPlan) && !(scriptWrapper instanceof ThreadGroup)) {
elementTree = tree.add(scriptWrapper); elementTree = tree.add(scriptWrapper);
} }
if (scriptWrapper instanceof TestElement) { if (!config.isOperating() && scriptWrapper instanceof ThreadGroup && !((ThreadGroup) scriptWrapper).isEnabled()) {
((TestElement) scriptWrapper).setName(this.getName()); LogUtil.info(((ThreadGroup) scriptWrapper).getName() + "是被禁用线程组不加入执行");
} } else {
if (CollectionUtils.isNotEmpty(hashTree)) { if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) { for (MsTestElement el : hashTree) {
el.toHashTree(elementTree, el.getHashTree(), config); el.toHashTree(elementTree, el.getHashTree(), config);
}
} }
} }
} }

View File

@ -115,7 +115,9 @@ public class ApiAutomationService {
if (map != null) { if (map != null) {
if (map.isEmpty()) { if (map.isEmpty()) {
List<String> ids = (List<String>) JSONPath.read(definition, "$..projectId"); List<String> ids = (List<String>) JSONPath.read(definition, "$..projectId");
idList.addAll(new HashSet<>(ids)); if (CollectionUtils.isNotEmpty(ids)) {
idList.addAll(new HashSet<>(ids));
}
} else { } else {
Set<String> set = d.getEnvironmentMap().keySet(); Set<String> set = d.getEnvironmentMap().keySet();
idList = new ArrayList<>(set); idList = new ArrayList<>(set);

View File

@ -447,6 +447,7 @@ public class ApiDefinitionService {
} }
HashTree hashTree = request.getTestElement().generateHashTree(config); HashTree hashTree = request.getTestElement().generateHashTree(config);
String runMode = ApiRunMode.DEFINITION.name(); String runMode = ApiRunMode.DEFINITION.name();
if (StringUtils.isNotBlank(request.getType()) && StringUtils.equals(request.getType(), ApiRunMode.API_PLAN.name())) { if (StringUtils.isNotBlank(request.getType()) && StringUtils.equals(request.getType(), ApiRunMode.API_PLAN.name())) {
runMode = ApiRunMode.API_PLAN.name(); runMode = ApiRunMode.API_PLAN.name();

View File

@ -372,20 +372,20 @@
<select id="getTestPlanCase" resultType="int"> <select id="getTestPlanCase" resultType="int">
select count(s) select count(s)
from ( from (
select id as s select tptc.id as s
from test_plan_test_case tptc from test_plan_test_case tptc join test_case on tptc.case_id = test_case.id
where tptc.plan_id = #{planId} where tptc.plan_id = #{planId}
union all union all
select id as s select tpas.id as s
from test_plan_api_scenario tpas from test_plan_api_scenario tpas join api_scenario on tpas.api_scenario_id = api_scenario.id
where tpas.test_plan_id = #{planId} where tpas.test_plan_id = #{planId} and api_scenario.status != 'Trash'
union all union all
select id as s select tpac.id as s
from test_plan_api_case tpac from test_plan_api_case tpac join api_test_case on tpac.api_case_id = api_test_case.id
where tpac.test_plan_id = #{planId} where tpac.test_plan_id = #{planId}
union all union all
select id as s select tplc.id as s
from test_plan_load_case tplc from test_plan_load_case tplc join load_test on tplc.load_case_id = load_test.id
where tplc.test_plan_id = #{planId} where tplc.test_plan_id = #{planId}
) as temp ) as temp
</select> </select>

View File

@ -161,12 +161,12 @@
#{value} #{value}
</foreach> </foreach>
</when> </when>
<otherwise> <when test="key=='status'">
and test_case_review_test_case.status in and test_case.review_status in
<foreach collection="values" item="value" separator="," open="(" close=")"> <foreach collection="values" item="value" separator="," open="(" close=")">
#{value} #{value}
</foreach> </foreach>
</otherwise> </when>
</choose> </choose>
</if> </if>
</foreach> </foreach>

View File

@ -5,7 +5,7 @@ import io.metersphere.security.ApiKeyFilter;
import io.metersphere.security.CsrfFilter; import io.metersphere.security.CsrfFilter;
import io.metersphere.security.UserModularRealmAuthenticator; import io.metersphere.security.UserModularRealmAuthenticator;
import io.metersphere.security.realm.LdapRealm; import io.metersphere.security.realm.LdapRealm;
import io.metersphere.security.realm.ShiroDBRealm; import io.metersphere.security.realm.LocalRealm;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy; import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator; import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.MemoryConstrainedCacheManager; import org.apache.shiro.cache.MemoryConstrainedCacheManager;
@ -70,7 +70,7 @@ public class ShiroConfig implements EnvironmentAware {
} }
/** /**
* securityManager 不用直接注入shiroDBRealm可能会导致事务失效 * securityManager 不用直接注入 Realm可能会导致事务失效
* 解决方法见 handleContextRefresh * 解决方法见 handleContextRefresh
* http://www.debugrun.com/a/NKS9EJQ.html * http://www.debugrun.com/a/NKS9EJQ.html
*/ */
@ -85,8 +85,8 @@ public class ShiroConfig implements EnvironmentAware {
@Bean @Bean
@DependsOn("lifecycleBeanPostProcessor") @DependsOn("lifecycleBeanPostProcessor")
public ShiroDBRealm shiroDBRealm() { public LocalRealm localRealm() {
return new ShiroDBRealm(); return new LocalRealm();
} }
@Bean @Bean
@ -135,10 +135,10 @@ public class ShiroConfig implements EnvironmentAware {
public void handleContextRefresh(ContextRefreshedEvent event) { public void handleContextRefresh(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext(); ApplicationContext context = event.getApplicationContext();
List<Realm> realmList = new ArrayList<>(); List<Realm> realmList = new ArrayList<>();
ShiroDBRealm shiroDBRealm = context.getBean(ShiroDBRealm.class); LocalRealm localRealm = context.getBean(LocalRealm.class);
LdapRealm ldapRealm = context.getBean(LdapRealm.class); LdapRealm ldapRealm = context.getBean(LdapRealm.class);
// 基本realm // 基本realm
realmList.add(shiroDBRealm); realmList.add(localRealm);
realmList.add(ldapRealm); realmList.add(ldapRealm);
context.getBean(DefaultWebSecurityManager.class).setRealms(realmList); context.getBean(DefaultWebSecurityManager.class).setRealms(realmList);
} }

View File

@ -0,0 +1,9 @@
package io.metersphere.excel.annotation;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface NotRequired {
}

View File

@ -20,8 +20,8 @@ public class TestCaseExcelData {
private String priority; private String priority;
@ExcelIgnore @ExcelIgnore
private String tags; private String tags;
@ExcelIgnore // @ExcelIgnore
private String method; // private String method;
@ExcelIgnore @ExcelIgnore
private String prerequisite; private String prerequisite;
@ExcelIgnore @ExcelIgnore

View File

@ -2,6 +2,7 @@ package io.metersphere.excel.domain;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ColumnWidth;
import io.metersphere.excel.annotation.NotRequired;
import lombok.Data; import lombok.Data;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
@ -40,13 +41,14 @@ public class TestCaseExcelDataCn extends TestCaseExcelData {
@ColumnWidth(50) @ColumnWidth(50)
@ExcelProperty("标签") @ExcelProperty("标签")
@NotRequired
@Length(min = 0, max = 1000) @Length(min = 0, max = 1000)
private String tags; private String tags;
@NotBlank(message = "{cannot_be_null}") // @NotBlank(message = "{cannot_be_null}")
@ExcelProperty("测试方式") // @ExcelProperty("测试方式")
@Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}") // @Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}")
private String method; // private String method;
@ColumnWidth(50) @ColumnWidth(50)
@ExcelProperty("前置条件") @ExcelProperty("前置条件")

View File

@ -2,6 +2,7 @@ package io.metersphere.excel.domain;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ColumnWidth;
import io.metersphere.excel.annotation.NotRequired;
import lombok.Data; import lombok.Data;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
@ -38,10 +39,16 @@ public class TestCaseExcelDataTw extends TestCaseExcelData {
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}") @Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}")
private String priority; private String priority;
@NotBlank(message = "{cannot_be_null}") @ColumnWidth(50)
@ExcelProperty("測試方式") @ExcelProperty("標簽")
@Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}") @NotRequired
private String method; @Length(min = 0, max = 1000)
private String tags;
// @NotBlank(message = "{cannot_be_null}")
// @ExcelProperty("測試方式")
// @Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}")
// private String method;
@ColumnWidth(50) @ColumnWidth(50)
@ExcelProperty("前置條件") @ExcelProperty("前置條件")

View File

@ -2,6 +2,7 @@ package io.metersphere.excel.domain;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ColumnWidth;
import io.metersphere.excel.annotation.NotRequired;
import lombok.Data; import lombok.Data;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
@ -39,10 +40,16 @@ public class TestCaseExcelDataUs extends TestCaseExcelData {
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}") @Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}")
private String priority; private String priority;
@NotBlank(message = "{cannot_be_null}") @ColumnWidth(50)
@ExcelProperty("Method") @ExcelProperty("Tag")
@Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}") @NotRequired
private String method; @Length(min = 0, max = 1000)
private String tags;
// @NotBlank(message = "{cannot_be_null}")
// @ExcelProperty("Method")
// @Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}")
// private String method;
@ColumnWidth(50) @ColumnWidth(50)
@ExcelProperty("Prerequisite") @ExcelProperty("Prerequisite")

View File

@ -6,15 +6,13 @@ import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import io.metersphere.excel.annotation.NotRequired;
import io.metersphere.excel.domain.ExcelErrData; import io.metersphere.excel.domain.ExcelErrData;
import io.metersphere.excel.domain.TestCaseExcelData; import io.metersphere.excel.domain.TestCaseExcelData;
import io.metersphere.excel.domain.UserExcelData;
import io.metersphere.excel.utils.ExcelValidateHelper; import io.metersphere.excel.utils.ExcelValidateHelper;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*; import java.util.*;
public abstract class EasyExcelListener<T> extends AnalysisEventListener<T> { public abstract class EasyExcelListener<T> extends AnalysisEventListener<T> {
@ -131,7 +129,10 @@ public abstract class EasyExcelListener<T> extends AnalysisEventListener<T> {
for (String v : excelProperty.value()) { for (String v : excelProperty.value()) {
value.append(v); value.append(v);
} }
result.add(value.toString()); // 检查是否必有的头部信息
if (field.getAnnotation(NotRequired.class) == null) {
result.add(value.toString());
}
} }
} }
return result; return result;
@ -140,4 +141,4 @@ public abstract class EasyExcelListener<T> extends AnalysisEventListener<T> {
public List<ExcelErrData<T>> getErrList() { public List<ExcelErrData<T>> getErrList() {
return errList; return errList;
} }
} }

View File

@ -53,9 +53,9 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
} }
} }
if (StringUtils.equals(data.getType(), TestCaseConstants.Type.Functional.getValue()) && StringUtils.equals(data.getMethod(), TestCaseConstants.Method.Auto.getValue())) { // if (StringUtils.equals(data.getType(), TestCaseConstants.Type.Functional.getValue()) && StringUtils.equals(data.getMethod(), TestCaseConstants.Method.Auto.getValue())) {
stringBuilder.append(Translator.get("functional_method_tip") + "; "); // stringBuilder.append(Translator.get("functional_method_tip") + "; ");
} // }
if (!userIds.contains(data.getMaintainer())) { if (!userIds.contains(data.getMaintainer())) {
stringBuilder.append(Translator.get("user_not_exists") + "" + data.getMaintainer() + "; "); stringBuilder.append(Translator.get("user_not_exists") + "" + data.getMaintainer() + "; ");
@ -144,12 +144,12 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
String[] stepRes = new String[1]; String[] stepRes = new String[1];
if (data.getStepDesc() != null) { if (data.getStepDesc() != null) {
stepDesc = data.getStepDesc().split("\n"); stepDesc = data.getStepDesc().split("\r\n");
} else { } else {
stepDesc[0] = ""; stepDesc[0] = "";
} }
if (data.getStepResult() != null) { if (data.getStepResult() != null) {
stepRes = data.getStepResult().split("\n"); stepRes = data.getStepResult().split("\r\n");
} else { } else {
stepRes[0] = ""; stepRes[0] = "";
} }

View File

@ -68,7 +68,7 @@ public class LdapController {
userService.addLdapUser(user); userService.addLdapUser(user);
} }
// 执行 ShiroDBRealm LDAP 登录逻辑 // 执行 LocalRealm LDAP 登录逻辑
LoginRequest loginRequest = new LoginRequest(); LoginRequest loginRequest = new LoginRequest();
loginRequest.setUsername(userId); loginRequest.setUsername(userId);
return userService.login(loginRequest); return userService.login(loginRequest);

View File

@ -34,9 +34,9 @@ import java.util.stream.Collectors;
* set realm * set realm
* </p> * </p>
*/ */
public class ShiroDBRealm extends AuthorizingRealm { public class LocalRealm extends AuthorizingRealm {
private Logger logger = LoggerFactory.getLogger(ShiroDBRealm.class); private Logger logger = LoggerFactory.getLogger(LocalRealm.class);
@Resource @Resource
private UserService userService; private UserService userService;

View File

@ -33,9 +33,7 @@ public class TestPlanApiCaseController {
@PostMapping("/relevance/list/{goPage}/{pageSize}") @PostMapping("/relevance/list/{goPage}/{pageSize}")
public Pager<List<ApiTestCaseDTO>> relevanceList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) { public Pager<List<ApiTestCaseDTO>> relevanceList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true); return testPlanApiCaseService.relevanceList(goPage, pageSize, request);
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return PageUtils.setPageInfo(page, testPlanApiCaseService.relevanceList(request));
} }
@GetMapping("/delete/{id}") @GetMapping("/delete/{id}")

View File

@ -131,8 +131,8 @@ public class TestCaseService {
.andNodePathEqualTo(testCase.getNodePath()) .andNodePathEqualTo(testCase.getNodePath())
.andTypeEqualTo(testCase.getType()) .andTypeEqualTo(testCase.getType())
.andMaintainerEqualTo(testCase.getMaintainer()) .andMaintainerEqualTo(testCase.getMaintainer())
.andPriorityEqualTo(testCase.getPriority()) .andPriorityEqualTo(testCase.getPriority());
.andMethodEqualTo(testCase.getMethod()); // .andMethodEqualTo(testCase.getMethod());
// if (StringUtils.isNotBlank(testCase.getNodeId())) { // if (StringUtils.isNotBlank(testCase.getNodeId())) {
// criteria.andNodeIdEqualTo(testCase.getTestId()); // criteria.andNodeIdEqualTo(testCase.getTestId());
@ -432,7 +432,7 @@ public class TestCaseService {
List<TestCaseExcelData> list = new ArrayList<>(); List<TestCaseExcelData> list = new ArrayList<>();
StringBuilder path = new StringBuilder(""); StringBuilder path = new StringBuilder("");
List<String> types = TestCaseConstants.Type.getValues(); List<String> types = TestCaseConstants.Type.getValues();
List<String> methods = TestCaseConstants.Method.getValues(); // List<String> methods = TestCaseConstants.Method.getValues();
SessionUser user = SessionUtils.getUser(); SessionUser user = SessionUtils.getUser();
for (int i = 1; i <= 5; i++) { for (int i = 1; i <= 5; i++) {
TestCaseExcelData data = new TestCaseExcelData(); TestCaseExcelData data = new TestCaseExcelData();
@ -442,11 +442,11 @@ public class TestCaseService {
data.setPriority("P" + i % 4); data.setPriority("P" + i % 4);
String type = types.get(i % 3); String type = types.get(i % 3);
data.setType(type); data.setType(type);
if (StringUtils.equals(TestCaseConstants.Type.Functional.getValue(), type)) { // if (StringUtils.equals(TestCaseConstants.Type.Functional.getValue(), type)) {
data.setMethod(TestCaseConstants.Method.Manual.getValue()); // data.setMethod(TestCaseConstants.Method.Manual.getValue());
} else { // } else {
data.setMethod(methods.get(i % 2)); // data.setMethod(methods.get(i % 2));
} // }
data.setPrerequisite(Translator.get("preconditions_optional")); data.setPrerequisite(Translator.get("preconditions_optional"));
data.setStepDesc("1. " + Translator.get("step_tip_separate") + data.setStepDesc("1. " + Translator.get("step_tip_separate") +
"\n2. " + Translator.get("step_tip_order") + "\n3. " + Translator.get("step_tip_optional")); "\n2. " + Translator.get("step_tip_order") + "\n3. " + Translator.get("step_tip_optional"));
@ -461,7 +461,7 @@ public class TestCaseService {
explain.setName(Translator.get("do_not_modify_header_order")); explain.setName(Translator.get("do_not_modify_header_order"));
explain.setNodePath(Translator.get("module_created_automatically")); explain.setNodePath(Translator.get("module_created_automatically"));
explain.setType(Translator.get("options") + "functional、performance、api"); explain.setType(Translator.get("options") + "functional、performance、api");
explain.setMethod(Translator.get("options") + "manual、auto"); // explain.setMethod(Translator.get("options") + "manual、auto");
explain.setPriority(Translator.get("options") + "P0、P1、P2、P3"); explain.setPriority(Translator.get("options") + "P0、P1、P2、P3");
explain.setMaintainer(Translator.get("please_input_workspace_member")); explain.setMaintainer(Translator.get("please_input_workspace_member"));
@ -483,7 +483,11 @@ public class TestCaseService {
private List<TestCaseExcelData> generateTestCaseExcel(TestCaseBatchRequest request) { private List<TestCaseExcelData> generateTestCaseExcel(TestCaseBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(), ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extTestCaseMapper.selectIds(query)); (query) -> extTestCaseMapper.selectIds(query));
List<OrderRequest> orderList = ServiceUtils.getDefaultOrder(request.getOrders()); QueryTestCaseRequest condition = request.getCondition();
List<OrderRequest> orderList = new ArrayList<>();
if (condition != null) {
orderList = ServiceUtils.getDefaultOrder(condition.getOrders());
}
OrderRequest order = new OrderRequest(); OrderRequest order = new OrderRequest();
order.setName("sort"); order.setName("sort");
order.setType("desc"); order.setType("desc");
@ -499,10 +503,10 @@ public class TestCaseService {
data.setNodePath(t.getNodePath()); data.setNodePath(t.getNodePath());
data.setPriority(t.getPriority()); data.setPriority(t.getPriority());
data.setType(t.getType()); data.setType(t.getType());
data.setMethod(t.getMethod()); // data.setMethod(t.getMethod());
data.setPrerequisite(t.getPrerequisite()); data.setPrerequisite(t.getPrerequisite());
data.setTags(t.getTags()); data.setTags(t.getTags());
if (t.getMethod().equals("manual")) { if (StringUtils.equals(t.getMethod(), "manual") || StringUtils.isBlank(t.getMethod())) {
String steps = t.getSteps(); String steps = t.getSteps();
String setp = ""; String setp = "";
setp = steps; setp = steps;
@ -520,8 +524,8 @@ public class TestCaseService {
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") + "\r\n");
result.append(num + "." + jsonArray.getJSONObject(j).getString("result") + "\n"); result.append(num + "." + jsonArray.getJSONObject(j).getString("result") + "\r\n");
} }
data.setStepDesc(step.toString()); data.setStepDesc(step.toString());
@ -530,19 +534,19 @@ public class TestCaseService {
result.setLength(0); result.setLength(0);
data.setRemark(t.getRemark()); data.setRemark(t.getRemark());
} else if (t.getMethod().equals("auto") && t.getType().equals("api")) { } else if ("auto".equals(t.getMethod()) && "api".equals(t.getType())) {
data.setStepDesc(""); data.setStepDesc("");
data.setStepResult(""); data.setStepResult("");
if (t.getTestId() != null && t.getTestId().equals("other")) { if (t.getTestId() != null && "other".equals(t.getTestId())) {
data.setRemark(t.getOtherTestName()); data.setRemark(t.getOtherTestName());
} else { } else {
data.setRemark("[" + t.getApiName() + "]" + "\n" + t.getRemark()); data.setRemark("[" + t.getApiName() + "]" + "\n" + t.getRemark());
} }
} else if (t.getMethod().equals("auto") && t.getType().equals("performance")) { } else if ("auto".equals(t.getMethod()) && "performance".equals(t.getType())) {
data.setStepDesc(""); data.setStepDesc("");
data.setStepResult(""); data.setStepResult("");
if (t.getTestId() != null && t.getTestId().equals("other")) { if (t.getTestId() != null && "other".equals(t.getTestId())) {
data.setRemark(t.getOtherTestName()); data.setRemark(t.getOtherTestName());
} else { } else {
data.setRemark(t.getPerformName()); data.setRemark(t.getPerformName());

View File

@ -2,6 +2,8 @@ package io.metersphere.track.service;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.definition.ApiTestCaseDTO; import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest; import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.RunDefinitionRequest; import io.metersphere.api.dto.definition.RunDefinitionRequest;
@ -18,7 +20,10 @@ import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.base.domain.TestPlanApiCaseExample; import io.metersphere.base.domain.TestPlanApiCaseExample;
import io.metersphere.base.mapper.TestPlanApiCaseMapper; import io.metersphere.base.mapper.TestPlanApiCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanApiCaseMapper; import io.metersphere.base.mapper.ext.ExtTestPlanApiCaseMapper;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest; import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -61,13 +66,15 @@ public class TestPlanApiCaseService {
return extTestPlanApiCaseMapper.getExecResultByPlanId(plan); return extTestPlanApiCaseMapper.getExecResultByPlanId(plan);
} }
public List<ApiTestCaseDTO> relevanceList(ApiTestCaseRequest request) { public Pager<List<ApiTestCaseDTO>> relevanceList(int goPage, int pageSize, ApiTestCaseRequest request) {
List<String> ids = apiTestCaseService.selectIdsNotExistsInPlan(request.getProjectId(), request.getPlanId()); List<String> ids = apiTestCaseService.selectIdsNotExistsInPlan(request.getProjectId(), request.getPlanId());
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
if (CollectionUtils.isEmpty(ids)) { if (CollectionUtils.isEmpty(ids)) {
return new ArrayList<>(); return PageUtils.setPageInfo(page, new ArrayList<>());
} }
request.setIds(ids); request.setIds(ids);
return apiTestCaseService.listSimple(request); request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return PageUtils.setPageInfo(page, apiTestCaseService.listSimple(request));
} }
public int delete(String id) { public int delete(String id) {

View File

@ -551,8 +551,8 @@ public class TestPlanService {
queryTestPlanRequest.setId(planId); queryTestPlanRequest.setId(planId);
TestPlanDTO testPlan = extTestPlanMapper.list(queryTestPlanRequest).get(0); TestPlanDTO testPlan = extTestPlanMapper.list(queryTestPlanRequest).get(0);
String projectName = getProjectNameByPlanId(planId); Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
testPlan.setProjectName(projectName); testPlan.setProjectName(project.getName());
TestCaseReport testCaseReport = testCaseReportMapper.selectByPrimaryKey(testPlan.getReportId()); TestCaseReport testCaseReport = testCaseReportMapper.selectByPrimaryKey(testPlan.getReportId());
JSONObject content = JSONObject.parseObject(testCaseReport.getContent()); JSONObject content = JSONObject.parseObject(testCaseReport.getContent());
@ -708,8 +708,8 @@ public class TestPlanService {
queryTestPlanRequest.setId(planId); queryTestPlanRequest.setId(planId);
TestPlanDTO testPlan = extTestPlanMapper.list(queryTestPlanRequest).get(0); TestPlanDTO testPlan = extTestPlanMapper.list(queryTestPlanRequest).get(0);
String projectName = getProjectNameByPlanId(planId); Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
testPlan.setProjectName(projectName); testPlan.setProjectName(project.getName());
TestCaseReport testCaseReport = testCaseReportMapper.selectByPrimaryKey(testPlan.getReportId()); TestCaseReport testCaseReport = testCaseReportMapper.selectByPrimaryKey(testPlan.getReportId());
JSONObject content = JSONObject.parseObject(testCaseReport.getContent()); JSONObject content = JSONObject.parseObject(testCaseReport.getContent());

View File

@ -1,13 +1,19 @@
package io.metersphere.track.service; package io.metersphere.track.service;
import io.metersphere.api.dto.automation.ScenarioStatus;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper; import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.utils.DateUtils; import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.MathUtils;
import io.metersphere.performance.base.ChartsData; import io.metersphere.performance.base.ChartsData;
import io.metersphere.track.dto.TestPlanDTOWithMetric;
import io.metersphere.track.response.BugStatustics; import io.metersphere.track.response.BugStatustics;
import io.metersphere.track.response.TestPlanBugCount; import io.metersphere.track.response.TestPlanBugCount;
import io.metersphere.track.response.TrackCountResult; import io.metersphere.track.response.TrackCountResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -28,13 +34,13 @@ public class TrackService {
@Resource @Resource
private TestPlanMapper testPlanMapper; private TestPlanMapper testPlanMapper;
@Resource @Resource
private TestPlanTestCaseMapper testPlanTestCaseMapper; private ExtTestPlanTestCaseMapper extTestPlanTestCaseMapper;
@Resource @Resource
private TestPlanLoadCaseMapper testPlanLoadCaseMapper; private TestPlanApiCaseService testPlanApiCaseService;
@Resource @Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper; private TestPlanScenarioCaseService testPlanScenarioCaseService;
@Resource @Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper; private TestPlanLoadCaseService testPlanLoadCaseService;
public List<TrackCountResult> countPriority(String projectId) { public List<TrackCountResult> countPriority(String projectId) {
return extTestCaseMapper.countPriority(projectId); return extTestCaseMapper.countPriority(projectId);
@ -132,11 +138,13 @@ public class TrackService {
int planBugSize = getPlanBugSize(plan.getId()); int planBugSize = getPlanBugSize(plan.getId());
testPlanBug.setBugSize(planBugSize); testPlanBug.setBugSize(planBugSize);
testPlanBug.setPassRage(getPlanPassRage(plan.getId(), planCaseSize)); double planPassRage = getPlanPassRage(plan.getId());
testPlanBug.setPassRage(planPassRage + "%");
list.add(testPlanBug); list.add(testPlanBug);
totalBugSize += planBugSize; totalBugSize += planBugSize;
totalCaseSize += planCaseSize; totalCaseSize += planCaseSize;
} }
bugStatustics.setList(list); bugStatustics.setList(list);
@ -156,13 +164,52 @@ public class TrackService {
return extTestCaseMapper.getTestPlanBug(planId); return extTestCaseMapper.getTestPlanBug(planId);
} }
private String getPlanPassRage(String planId, int totalSize) { private double getPlanPassRage(String planId) {
if (totalSize == 0) { TestPlanDTOWithMetric testPlan = new TestPlanDTOWithMetric();
return "-"; testPlan.setTested(0);
} testPlan.setPassed(0);
int passSize = extTestCaseMapper.getTestPlanPassCase(planId); testPlan.setTotal(0);
float rage = (float) passSize * 100 / totalSize;
DecimalFormat df = new DecimalFormat("0.0"); List<String> functionalExecResults = extTestPlanTestCaseMapper.getExecResultByPlanId(planId);
return df.format(rage) + "%"; functionalExecResults.forEach(item -> {
if (!StringUtils.equals(item, TestPlanTestCaseStatus.Prepare.name())
&& !StringUtils.equals(item, TestPlanTestCaseStatus.Underway.name())) {
testPlan.setTested(testPlan.getTested() + 1);
if (StringUtils.equals(item, TestPlanTestCaseStatus.Pass.name())) {
testPlan.setPassed(testPlan.getPassed() + 1);
}
}
});
List<String> apiExecResults = testPlanApiCaseService.getExecResultByPlanId(planId);
apiExecResults.forEach(item -> {
if (StringUtils.isNotBlank(item)) {
testPlan.setTested(testPlan.getTested() + 1);
if (StringUtils.equals(item, "success")) {
testPlan.setPassed(testPlan.getPassed() + 1);
}
}
});
List<String> scenarioExecResults = testPlanScenarioCaseService.getExecResultByPlanId(planId);
scenarioExecResults.forEach(item -> {
if (StringUtils.isNotBlank(item)) {
testPlan.setTested(testPlan.getTested() + 1);
if (StringUtils.equals(item, ScenarioStatus.Success.name())) {
testPlan.setPassed(testPlan.getPassed() + 1);
}
}
});
List<String> loadResults = testPlanLoadCaseService.getStatus(planId);
loadResults.forEach(item -> {
if (StringUtils.isNotBlank(item)) {
testPlan.setTested(testPlan.getTested() + 1);
if (StringUtils.equals(item, "success")) {
testPlan.setPassed(testPlan.getPassed() + 1);
}
}
});
return MathUtils.getPercentWithDecimal(testPlan.getTested() == 0 ? 0 : testPlan.getPassed() * 1.0 / testPlan.getTested());
} }
} }

@ -1 +1 @@
Subproject commit adefde265ff12d4ea909353c3f46008f8a8e17e7 Subproject commit c9fd084c8f4453d7697677a79d9a0a953c045e38

View File

@ -161,4 +161,6 @@ UPDATE file_metadata JOIN (SELECT file_id, project_id
SET file_metadata.project_id = temp.project_id; SET file_metadata.project_id = temp.project_id;
-- add execution_times testPlan -- add execution_times testPlan
alter table test_plan alter table test_plan
add execution_times int null; add execution_times int null;
alter table test_case modify method varchar(15) null comment 'Test case method type';

View File

@ -54,10 +54,10 @@
}, },
methods: { methods: {
remove() { remove() {
this.$emit('remove', this.jsr223Processor, this.node); this.$emit('remove', this.request, this.node);
}, },
copyRow() { copyRow() {
this.$emit('copyRow', this.jsr223Processor, this.node); this.$emit('copyRow', this.request, this.node);
}, },
active() { active() {
this.request.active = !this.request.active; this.request.active = !this.request.active;

View File

@ -194,7 +194,7 @@
this.$emit('batchEditCase'); this.$emit('batchEditCase');
}, },
deleteCase(index, row) { deleteCase(index, row) {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + row.name + " ", '', { this.$alert(this.$t('api_test.definition.request.delete_case_confirm') + ' ' + row.name + " ", '', {
confirmButtonText: this.$t('commons.confirm'), confirmButtonText: this.$t('commons.confirm'),
callback: (action) => { callback: (action) => {
if (action === 'confirm') { if (action === 'confirm') {
@ -305,10 +305,6 @@
row.id = data.id; row.id = data.id;
row.createTime = data.createTime; row.createTime = data.createTime;
row.updateTime = data.updateTime; row.updateTime = data.updateTime;
if (!row.message) {
this.$success(this.$t('commons.save_success'));
this.$emit('refresh');
}
}); });
}, },
saveTestCase(row) { saveTestCase(row) {
@ -317,7 +313,6 @@
} else { } else {
this.saveCase(row); this.saveCase(row);
} }
}, },
showInput(row) { showInput(row) {
// row.type = "create"; // row.type = "create";

View File

@ -8,8 +8,7 @@
<div class="ms-drawer-header"> <div class="ms-drawer-header">
<slot name="header"></slot> <slot name="header"></slot>
<i v-if="isShowClose" class="el-icon-close" @click="close"/> <i v-if="isShowClose" class="el-icon-close" @click="close"/>
<font-awesome-icon v-if="!isFullScreen && showFullScreen" class="alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="fullScreen"/> <ms-full-screen-button v-if="showFullScreen" :is-full-screen.sync="isFullScreen"/>
<font-awesome-icon v-if="isFullScreen && showFullScreen" class="alt-ico" :icon="['fa', 'compress-alt']" size="lg" @click="unFullScreen"/>
</div> </div>
<div class="ms-drawer-body"> <div class="ms-drawer-body">
<slot></slot> <slot></slot>
@ -23,9 +22,10 @@
import MsRight2LeftDragBar from "./dragbar/MsRight2LeftDragBar"; import MsRight2LeftDragBar from "./dragbar/MsRight2LeftDragBar";
import MsLeft2RightDragBar from "./dragbar/MsLeft2RightDragBar"; import MsLeft2RightDragBar from "./dragbar/MsLeft2RightDragBar";
import MsBottom2TopDragBar from "./dragbar/MsBottom2TopDragBar"; import MsBottom2TopDragBar from "./dragbar/MsBottom2TopDragBar";
import MsFullScreenButton from "@/business/components/common/components/MsFullScreenButton";
export default { export default {
name: "MsDrawer", name: "MsDrawer",
components: {MsBottom2TopDragBar, MsLeft2RightDragBar, MsRight2LeftDragBar}, components: {MsFullScreenButton, MsBottom2TopDragBar, MsLeft2RightDragBar, MsRight2LeftDragBar},
data() { data() {
return { return {
x: 0, x: 0,
@ -74,6 +74,15 @@
mounted() { mounted() {
this.init(); this.init();
}, },
watch: {
isFullScreen() {
if (this.isFullScreen) {
this.fullScreen()
} else {
this.unFullScreen();
}
}
},
methods: { methods: {
init() { init() {
// todo // todo
@ -123,12 +132,10 @@
this.originalH = this.h; this.originalH = this.h;
this.w = document.body.clientWidth; this.w = document.body.clientWidth;
this.h = document.body.clientHeight; this.h = document.body.clientHeight;
this.isFullScreen = true;
}, },
unFullScreen() { unFullScreen() {
this.w = this.originalW; this.w = this.originalW;
this.h = this.originalH; this.h = this.originalH;
this.isFullScreen = false;
}, },
close() { close() {
this.$emit('close') this.$emit('close')
@ -206,18 +213,10 @@
color: red; color: red;
} }
.alt-ico { /deep/ .alt-ico {
position: absolute; position: absolute;
font-size: 15px;
right: 40px; right: 40px;
top: 15px; top: 15px;
color: #8c939d;
} }
.alt-ico:hover {
color: black;
font-size: 18px;
}
</style> </style>

View File

@ -0,0 +1,37 @@
<template>
<span class="fulls-screen-btn">
<font-awesome-icon v-if="!isFullScreen" class="alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="change(true)"/>
<font-awesome-icon v-if="isFullScreen" class="alt-ico" :icon="['fa', 'compress-alt']" size="lg" @click="change(false)"/>
</span>
</template>
<script>
export default {
name: "MsFullScreenButton",
props: {
isFullScreen: {
type: Boolean,
default: false
},
},
methods: {
change(bool) {
this.$emit("update:isFullScreen", bool);
}
}
}
</script>
<style scoped>
.alt-ico:hover {
color: black;
font-size: 18px;
}
.alt-ico {
font-size: 15px;
color: #8c939d;
}
</style>

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="minder"> <div class="minder" :class="{'full-screen': isFullScreen}">
<ms-full-screen-button :is-full-screen.sync="isFullScreen"/>
<minder-editor <minder-editor
v-if="isActive" v-if="isActive"
class="minder-container" class="minder-container"
:import-json="importJson" :import-json="importJson"
:height="700"
:progress-enable="false" :progress-enable="false"
:tags="tags" :tags="tags"
:distinct-tags="distinctTags" :distinct-tags="distinctTags"
@ -15,9 +15,10 @@
<script> <script>
import MsFullScreenButton from "@/business/components/common/components/MsFullScreenButton";
export default { export default {
name: "MsModuleMinder", name: "MsModuleMinder",
components: {}, components: {MsFullScreenButton},
props: { props: {
treeNodes: { treeNodes: {
type: Array, type: Array,
@ -58,10 +59,11 @@ export default {
}, },
"template":"default" "template":"default"
}, },
isActive: true isActive: true,
isFullScreen: false
} }
}, },
mounted() { created() {
}, },
watch: { watch: {
dataMap() { dataMap() {
@ -128,4 +130,33 @@ export default {
bottom: auto; bottom: auto;
top: 30px; top: 30px;
} }
.minder {
position: relative;
}
.fulls-screen-btn {
position: absolute;
top: 10px;
right: 10px;
z-index: 1;
}
.full-screen {
position: fixed;
top: 0px;
left: 0px;
width: 100%;
background: white;
height: 100vh;
z-index: 999999;
}
.full-screen >>> .minder-container {
height: calc(100vh - 109px) !important;
}
.full-screen .fulls-screen-btn {
right: 30px;
}
</style> </style>

View File

@ -103,16 +103,16 @@ export default {
.active { .active {
border: solid 1px #6d317c; border: solid 1px #6d317c;
background-color: var(--color); background-color: var(--primary_color);
color: #FFFFFF; color: #FFFFFF;
} }
.case-button { .case-button {
border-left: solid 1px var(--color); border-left: solid 1px var(--primary_color);
} }
.item{ .item{
border: solid 1px var(--color); border: solid 1px var(--primary_color);
} }
</style> </style>

View File

@ -10,7 +10,7 @@
</template> </template>
<search-list :current-project.sync="currentProject"/> <search-list :current-project.sync="currentProject"/>
<el-divider/> <el-divider/>
<el-menu-item :index="'/setting/project/create'"> <el-menu-item :index="'/setting/project/create'" v-permission="['test_manager','test_user']">
<font-awesome-icon :icon="['fa', 'plus']"/> <font-awesome-icon :icon="['fa', 'plus']"/>
<span style="padding-left: 7px;">{{ $t("project.create") }}</span> <span style="padding-left: 7px;">{{ $t("project.create") }}</span>
</el-menu-item> </el-menu-item>

View File

@ -159,7 +159,7 @@ export default {
data() { data() {
return { return {
timeout: 60000, timeout: 60000,
responseTimeout: null, responseTimeout: 60000,
statusCode: [], statusCode: [],
domains: [], domains: [],
params: [], params: [],

View File

@ -42,12 +42,11 @@
<br> <br>
<div v-if="threadGroup.threadType === 'DURATION'"> <div v-if="threadGroup.threadType === 'DURATION'">
<el-form-item :label="$t('load_test.duration')"> <el-form-item :label="$t('load_test.duration')">
<!-- 最多两天的测试时长 -->
<el-input-number <el-input-number
:disabled="isReadOnly" :disabled="isReadOnly"
v-model="threadGroup.duration" v-model="threadGroup.duration"
:min="1" :min="1"
:max="99999" :max="9999"
@change="calculateChart(threadGroup)" @change="calculateChart(threadGroup)"
size="mini"/> size="mini"/>
</el-form-item> </el-form-item>

View File

@ -8,6 +8,7 @@
@setTreeNodes="setTreeNodes" @setTreeNodes="setTreeNodes"
@exportTestCase="exportTestCase" @exportTestCase="exportTestCase"
@saveAsEdit="editTestCase" @saveAsEdit="editTestCase"
@refreshAll="refreshAll"
:type="'edit'" :type="'edit'"
ref="nodeTree" ref="nodeTree"
/> />

View File

@ -101,7 +101,6 @@ export default {
this.$emit("refreshTable"); this.$emit("refreshTable");
}, },
refreshAll() { refreshAll() {
this.selectRows.clear();
this.$emit('refreshAll'); this.$emit('refreshAll');
}, },
handleCommand(e) { handleCommand(e) {

View File

@ -94,8 +94,8 @@
<span class="default-property"> <span class="default-property">
未通过 未通过
{{"\xa0\xa0"}} {{"\xa0\xa0"}}
<el-link type="info" @click="redirectPage('Pass')" target="_blank" style="color: #000000"> <el-link type="info" @click="redirectPage('UnPass')" target="_blank" style="color: #000000">
{{trackCountData.passCount}} {{trackCountData.unPassCount}}
</el-link> </el-link>
</span> </span>
</el-col> </el-col>
@ -103,8 +103,8 @@
<span class="main-property"> <span class="main-property">
已通过 已通过
{{"\xa0\xa0"}} {{"\xa0\xa0"}}
<el-link type="info" @click="redirectPage('UnPass')" target="_blank" style="color: #000000"> <el-link type="info" @click="redirectPage('Pass')" target="_blank" style="color: #000000">
{{trackCountData.unPassCount}} {{trackCountData.passCount}}
</el-link> </el-link>
</span> </span>
</el-col> </el-col>

View File

@ -2,7 +2,7 @@
<el-card class="table-card" v-loading="result.loading" body-style="padding:10px;"> <el-card class="table-card" v-loading="result.loading" body-style="padding:10px;">
<div slot="header"> <div slot="header">
<span class="title"> <span class="title">
遗留缺陷统计 用例评审
</span> </span>
<ms-table-button :is-tester-permission="true" v-if="!showMyCreator" icon="el-icon-view" <ms-table-button :is-tester-permission="true" v-if="!showMyCreator" icon="el-icon-view"
:content="$t('test_track.review.my_create')" @click="searchMyCreator" style="float: right"/> :content="$t('test_track.review.my_create')" @click="searchMyCreator" style="float: right"/>

View File

@ -310,8 +310,6 @@ export default {
} }
item.passRate=item.passRate+'%' item.passRate=item.passRate+'%'
}) })
console.log(this.tableData)
}); });
}, },
copyData(status) { copyData(status) {

View File

@ -10,7 +10,7 @@
@dataChange="changePlan"/> @dataChange="changePlan"/>
</template> </template>
<template v-slot:menu> <template v-slot:menu>
<el-menu v-if="isMenuShow" active-text-color="#6d317c" :default-active="activeIndex" <el-menu v-if="isMenuShow" :active-text-color="color" :default-active="activeIndex"
class="el-menu-demo header-menu" mode="horizontal" @select="handleSelect"> class="el-menu-demo header-menu" mode="horizontal" @select="handleSelect">
<el-menu-item index="functional">功能测试用例</el-menu-item> <el-menu-item index="functional">功能测试用例</el-menu-item>
<el-menu-item index="api">接口测试用例</el-menu-item> <el-menu-item index="api">接口测试用例</el-menu-item>
@ -71,6 +71,9 @@
computed: { computed: {
planId: function () { planId: function () {
return this.$route.params.planId; return this.$route.params.planId;
},
color: function () {
return `var(--primary_color)`
} }
}, },
watch: { watch: {

View File

@ -34,6 +34,7 @@
import MsDialogFooter from '../../../../../common/components/MsDialogFooter' import MsDialogFooter from '../../../../../common/components/MsDialogFooter'
import SelectMenu from "../../../../common/SelectMenu"; import SelectMenu from "../../../../common/SelectMenu";
import RelevanceDialog from "./RelevanceDialog"; import RelevanceDialog from "./RelevanceDialog";
import {getCurrentProjectID} from "@/common/js/utils";
export default { export default {
name: "TestCaseRelevanceBase", name: "TestCaseRelevanceBase",
@ -93,10 +94,17 @@
this.result = this.$get("/project/listAll", res => { this.result = this.$get("/project/listAll", res => {
let data = res.data; let data = res.data;
if (data) { if (data) {
const index = data.findIndex(d => d.id === getCurrentProjectID());
this.projects = data; this.projects = data;
this.projectId = data[0].id; if (index !== -1) {
this.projectName = data[0].name; this.projectId = data[index].id;
this.changeProject(data[0]); this.projectName = data[index].name;
this.changeProject(data[index]);
} else {
this.projectId = data[0].id;
this.projectName = data[0].name;
this.changeProject(data[0]);
}
} }
}) })
}, },

View File

@ -591,17 +591,23 @@ export default {
const project = res.data; const project = res.data;
if (project.tapdId) { if (project.tapdId) {
this.hasTapdId = true; this.hasTapdId = true;
this.result = this.$get("/issues/tapd/user/" + this.testCase.caseId, response => { this.result = this.$get("/issues/tapd/user/" + this.testCase.caseId).then(response => {
this.users = response.data; this.users = response.data.data;
}).catch(() => {
console.log("get tapd user error.");
}) })
} }
if (project.zentaoId) { if (project.zentaoId) {
this.hasZentaoId = true; this.hasZentaoId = true;
this.result = this.$get("/issues/zentao/builds/" + this.testCase.caseId, response => { this.result = this.$get("/issues/zentao/builds/" + this.testCase.caseId).then(response => {
this.Builds = response.data; this.Builds = response.data.data;
}).catch(() => {
console.log("get zentao builds error.");
}) })
this.result = this.$get("/issues/zentao/user/" + this.testCase.caseId, response => { this.result = this.$get("/issues/zentao/user/" + this.testCase.caseId).then(response => {
this.zentaoUsers = response.data; this.zentaoUsers = response.data.data;
}).catch(() => {
console.log("get zentao user error.");
}) })
} }
}) })
@ -649,8 +655,10 @@ export default {
this.testCase.zentaoAssigned = ""; this.testCase.zentaoAssigned = "";
}, },
getIssues(caseId) { getIssues(caseId) {
this.result = this.$get("/issues/get/" + caseId, response => { this.result = this.$get("/issues/get/" + caseId).then(response => {
this.issues = response.data; this.issues = response.data.data;
}).catch(() => {
console.log("get issues error")
}) })
}, },
closeIssue(row) { closeIssue(row) {

View File

@ -9,7 +9,7 @@
@dataChange="changeReview"/> @dataChange="changeReview"/>
</template> </template>
<template v-slot:menu> <template v-slot:menu>
<el-menu v-if="isMenuShow" active-text-color="#6d317c" <el-menu v-if="isMenuShow" :active-text-color="color"
class="el-menu-demo header-menu" mode="horizontal" @select="handleSelect" class="el-menu-demo header-menu" mode="horizontal" @select="handleSelect"
:default-active="activeIndex"> :default-active="activeIndex">
<el-menu-item index="functional">功能测试用例</el-menu-item> <el-menu-item index="functional">功能测试用例</el-menu-item>
@ -78,6 +78,9 @@ export default {
computed: { computed: {
reviewId: function () { reviewId: function () {
return this.$route.params.reviewId; return this.$route.params.reviewId;
},
color: function () {
return `var(--primary_color)`
} }
}, },
mounted() { mounted() {

View File

@ -62,19 +62,19 @@ html,body {
/* <-- 表格拖拽表头调整宽度,在 t-bable 上添加 border 属性,并添加 adjust-table 类名 */ /* <-- 表格拖拽表头调整宽度,在 t-bable 上添加 border 属性,并添加 adjust-table 类名 */
.adjust-table td { .adjust-table td {
border-right: 0; border-right: 0 !important;
} }
.adjust-table th { .adjust-table th {
border-right-color: white; border-right-color: white !important;
} }
.adjust-table { .adjust-table {
border-color: white; border-color: white !important;
} }
.adjust-table:after { .adjust-table:after {
background-color: white; background-color: white !important;
} }
.adjust-table th:not([class*="el-table-column--selection"]):hover:after { .adjust-table th:not([class*="el-table-column--selection"]):hover:after {
@ -84,11 +84,11 @@ html,body {
right: 0; right: 0;
height: 50%; height: 50%;
width: 2px; width: 2px;
background-color: #EBEEF5; background-color: #EBEEF5 !important;
} }
.adjust-table tr:hover td { .adjust-table tr:hover td {
border-right: 0; border-right: 0 !important;
} }
/* 表格拖拽表头调整宽度 --> */ /* 表格拖拽表头调整宽度 --> */

View File

@ -624,6 +624,7 @@ export default {
res_param: "Response content", res_param: "Response content",
batch_delete: "Batch deletion", batch_delete: "Batch deletion",
delete_confirm: "Confirm deletion", delete_confirm: "Confirm deletion",
delete_case_confirm: "Confirm case deletion",
delete_confirm_step: "Confirm deletion step", delete_confirm_step: "Confirm deletion step",
assertions_rule: "Assertion rule", assertions_rule: "Assertion rule",
response_header: "Response header", response_header: "Response header",

View File

@ -625,6 +625,7 @@ export default {
res_param: "响应内容", res_param: "响应内容",
batch_delete: "批量删除", batch_delete: "批量删除",
delete_confirm: "确认删除接口", delete_confirm: "确认删除接口",
delete_case_confirm: "确认删除用例",
delete_confirm_step: "确认删除步骤", delete_confirm_step: "确认删除步骤",
assertions_rule: "断言规则", assertions_rule: "断言规则",
response_header: "响应头", response_header: "响应头",

View File

@ -624,6 +624,7 @@ export default {
res_param: "響應內容", res_param: "響應內容",
batch_delete: "批量刪除", batch_delete: "批量刪除",
delete_confirm: "確認刪除接口", delete_confirm: "確認刪除接口",
delete_case_confirm: "確認刪除用例",
delete_confirm_step: "確認刪除步驟", delete_confirm_step: "確認刪除步驟",
assertions_rule: "斷言規則", assertions_rule: "斷言規則",
response_header: "響應頭", response_header: "響應頭",