fix: 解决冲突

This commit is contained in:
chenjianxing 2020-12-10 18:08:37 +08:00
commit abf807ad0c
128 changed files with 2734 additions and 1338 deletions

View File

@ -60,5 +60,5 @@ jobs:
username: metersphere
password: ${{ secrets.DOCKER_HUB_TOKEN }}
repository: metersphere/metersphere
tag_with_ref: true
tags: ${{ env.GITHUB_REF_SLUG }}
build_args: MS_VERSION=${{ env.GITHUB_REF_SLUG }}-${{ env.GITHUB_SHA_SHORT }}

View File

@ -2,10 +2,7 @@ package io.metersphere.api.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.base.domain.ApiScenario;
@ -19,7 +16,6 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
@RestController
@ -83,9 +79,14 @@ public class ApiAutomationController {
}
@PostMapping("/getReference")
public List<ApiScenario> getReference(@RequestBody ApiScenarioRequest request) {
public ReferenceDTO getReference(@RequestBody ApiScenarioRequest request) {
return apiAutomationService.getReference(request);
}
@PostMapping("/scenario/plan")
public String addScenarioToPlan(@RequestBody SaveApiPlanRequest request) {
return apiAutomationService.addScenarioToPlan(request);
}
}

View File

@ -4,6 +4,8 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.ReferenceDTO;
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
@ -62,7 +64,6 @@ public class ApiDefinitionController {
apiDefinitionService.removeToGc(ids);
}
@GetMapping("/get/{id}")
public ApiDefinition get(@PathVariable String id) {
return apiDefinitionService.get(id);
@ -94,5 +95,9 @@ public class ApiDefinitionController {
return apiDefinitionService.apiTestImport(file, request);
}
@PostMapping("/getReference")
public ReferenceDTO getReference(@RequestBody ApiScenarioRequest request) {
return apiDefinitionService.getReference(request);
}
}

View File

@ -4,6 +4,8 @@ import io.metersphere.base.domain.ApiTestReport;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class APIReportResult extends ApiTestReport {
@ -14,5 +16,7 @@ public class APIReportResult extends ApiTestReport {
private String userName;
private List<String> scenarioIds;
private String content;
}

View File

@ -0,0 +1,16 @@
package io.metersphere.api.dto.automation;
import io.metersphere.base.domain.ApiScenario;
import io.metersphere.track.dto.TestPlanDTO;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class ReferenceDTO {
List<ApiScenario> scenarioList;
List<TestPlanDTO> testPlanList;
}

View File

@ -15,5 +15,7 @@ public class RunScenarioRequest {
private String environmentId;
private String triggerMode;
private List<String> scenarioIds;
}

View File

@ -0,0 +1,14 @@
package io.metersphere.api.dto.automation;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class SaveApiPlanRequest {
private List<String> planIds;
private List<String> apiIds;
private List<String> scenarioIds;
}

View File

@ -17,7 +17,10 @@ import io.metersphere.commons.utils.CommonBeanFactory;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import org.apache.jmeter.config.Arguments;
import java.util.LinkedList;
import java.util.List;
@ -40,11 +43,14 @@ public class MsScenario extends MsTestElement {
@JSONField(ordinal = 13)
private List<KeyValue> variables;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (environmentId != null) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class));
}
if (CollectionUtils.isNotEmpty(this.getVariables())) {
config.setVariables(this.variables);
}
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
return;
@ -66,10 +72,29 @@ public class MsScenario extends MsTestElement {
ex.printStackTrace();
}
}
// 场景变量
if (CollectionUtils.isNotEmpty(this.getVariables())) {
tree.add(arguments());
}
if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.getHashTree(), config);
}
}
}
private Arguments arguments() {
Arguments arguments = new Arguments();
arguments.setEnabled(true);
arguments.setName(name + "Variables");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
variables.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
);
return arguments;
}
}

View File

@ -4,6 +4,9 @@ import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.assertions.MsAssertions;
import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager;
@ -16,7 +19,9 @@ import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.definition.request.timer.MsConstantTimer;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import lombok.Data;
import org.apache.jmeter.protocol.http.control.AuthManager;
@ -51,7 +56,7 @@ import java.util.List;
MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class,
MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class}, typeKey = "type")
@Data
public class MsTestElement {
public abstract class MsTestElement {
private String type;
@JSONField(ordinal = 1)
private String id;
@ -71,7 +76,7 @@ public class MsTestElement {
private LinkedList<MsTestElement> hashTree;
// 公共环境逐层传递如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.hashTree, config);
}
@ -95,7 +100,7 @@ public class MsTestElement {
return null;
}
public HashTree generateHashTree(EnvironmentConfig config) {
public HashTree generateHashTree(ParameterConfig config) {
HashTree jmeterTestPlanHashTree = new ListedHashTree();
this.toHashTree(jmeterTestPlanHashTree, this.hashTree, config);
return jmeterTestPlanHashTree;
@ -103,10 +108,22 @@ public class MsTestElement {
public HashTree generateHashTree() {
HashTree jmeterTestPlanHashTree = new ListedHashTree();
this.toHashTree(jmeterTestPlanHashTree, this.hashTree, null);
this.toHashTree(jmeterTestPlanHashTree, this.hashTree, new ParameterConfig());
return jmeterTestPlanHashTree;
}
public void getRefElement(MsTestElement element) {
try {
ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ApiDefinitionWithBLOBs apiDefinition = apiDefinitionService.getBLOBs(this.getId());
element = mapper.readValue(apiDefinition.getRequest(), new TypeReference<MsTestElement>() {});
hashTree.add(element);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@ -1,7 +1,6 @@
package io.metersphere.api.dto.definition.request;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -19,7 +18,7 @@ import java.util.List;
public class MsTestPlan extends MsTestElement {
private String type = "TestPlan";
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
final HashTree testPlanTree = tree.add(getPlan());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {

View File

@ -1,7 +1,6 @@
package io.metersphere.api.dto.definition.request;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -19,7 +18,7 @@ import java.util.List;
public class MsThreadGroup extends MsTestElement {
private String type = "ThreadGroup";
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
final HashTree groupTree = tree.add(getThreadGroup());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {

View File

@ -0,0 +1,15 @@
package io.metersphere.api.dto.definition.request;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import lombok.Data;
import java.util.List;
@Data
public class ParameterConfig {
// 环境配置
private EnvironmentConfig config;
// 公共场景参数
private List<KeyValue> variables;
}

View File

@ -2,7 +2,7 @@ package io.metersphere.api.dto.definition.request.assertions;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -24,7 +24,7 @@ public class MsAssertions extends MsTestElement {
private MsAssertionDuration duration;
private String type = "Assertions";
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
addAssertions(tree);
}

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
@ -50,7 +51,7 @@ public class MsAuthManager extends MsTestElement {
@JSONField(ordinal = 18)
private String environment;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
AuthManager authManager = new AuthManager();
authManager.setEnabled(true);
authManager.setName(this.getUsername() + "AuthManager");
@ -63,8 +64,8 @@ public class MsAuthManager extends MsTestElement {
if (environment != null) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environmentWithBLOBs = environmentService.get(environment);
config = JSONObject.parseObject(environmentWithBLOBs.getConfig(), EnvironmentConfig.class);
this.url = config.getHttpConfig().getProtocol() + "://" + config.getHttpConfig().getSocket();
EnvironmentConfig envConfig = JSONObject.parseObject(environmentWithBLOBs.getConfig(), EnvironmentConfig.class);
this.url = envConfig.getHttpConfig().getProtocol() + "://" + envConfig.getHttpConfig().getSocket();
}
}
auth.setDomain(this.domain);

View File

@ -3,8 +3,8 @@ package io.metersphere.api.dto.definition.request.configurations;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -25,7 +25,7 @@ public class MsHeaderManager extends MsTestElement {
@JSONField(ordinal = 10)
private List<KeyValue> headers;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
HeaderManager headerManager = new HeaderManager();
headerManager.setEnabled(true);
headerManager.setName(this.getName() + "Headers");

View File

@ -2,7 +2,7 @@ package io.metersphere.api.dto.definition.request.controller;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -25,7 +25,7 @@ public class MsIfController extends MsTestElement {
private String operator;
private String value;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
final HashTree groupTree = tree.add(ifController());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {

View File

@ -2,6 +2,7 @@ package io.metersphere.api.dto.definition.request.dns;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.environment.Host;
@ -23,7 +24,7 @@ import java.util.List;
@JSONType(typeName = "DNSCacheManager")
public class MsDNSCacheManager extends MsTestElement {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.getHashTree(), config);
}

View File

@ -2,7 +2,7 @@ package io.metersphere.api.dto.definition.request.extract;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -24,7 +24,7 @@ public class MsExtract extends MsTestElement {
private List<MsExtractXPath> xpath;
private String type = "Extract";
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
addRequestExtractors(tree);
}

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.processors;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -26,7 +26,7 @@ public class MsJSR223Processor extends MsTestElement {
@JSONField(ordinal = 11)
private String scriptLanguage;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
JSR223Sampler processor = new JSR223Sampler();
processor.setEnabled(true);
processor.setName(this.getName() + "JSR223Processor");

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.processors.post;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -27,7 +27,7 @@ public class MsJSR223PostProcessor extends MsTestElement {
private String scriptLanguage;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
JSR223PostProcessor processor = new JSR223PostProcessor();
processor.setEnabled(true);
processor.setName(this.getName() + "JSR223PostProcessor");

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.processors.pre;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -26,7 +26,7 @@ public class MsJSR223PreProcessor extends MsTestElement {
@JSONField(ordinal = 11)
private String scriptLanguage;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
JSR223PreProcessor processor = new JSR223PreProcessor();
processor.setEnabled(true);
processor.setName(this.getName() + "JSR223PreProcessor");

View File

@ -7,11 +7,11 @@ import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
import io.github.ningyu.jmeter.plugin.dubbo.sample.MethodArgument;
import io.github.ningyu.jmeter.plugin.util.Constants;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConfigCenter;
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConsumerAndService;
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsRegistryCenter;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -51,7 +51,14 @@ public class MsDubboSampler extends MsTestElement {
@JSONField(ordinal = 59)
private List<KeyValue> attachmentArgs;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
return;
}
if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
this.getRefElement(this);
}
final HashTree testPlanTree = new ListedHashTree();
testPlanTree.add(dubboConfig());
tree.set(dubboSample(), testPlanTree);

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.KeyValue;
@ -27,7 +28,11 @@ import org.apache.jorphan.collections.HashTree;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Data
@EqualsAndHashCode(callSuper = true)
@ -80,7 +85,10 @@ public class MsHTTPSamplerProxy extends MsTestElement {
@JSONField(ordinal = 24)
private List<KeyValue> arguments;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
this.getRefElement(this);
}
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
sampler.setEnabled(true);
sampler.setName(this.getName());
@ -96,23 +104,25 @@ public class MsHTTPSamplerProxy extends MsTestElement {
if (useEnvironment != null) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(useEnvironment);
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class));
}
try {
if (config != null) {
if (config != null && config.getConfig() != null) {
String url = "";
sampler.setDomain(config.getHttpConfig().getDomain());
sampler.setPort(config.getHttpConfig().getPort());
sampler.setProtocol(config.getHttpConfig().getProtocol());
url = config.getHttpConfig().getProtocol() + "://" + config.getHttpConfig().getSocket();
sampler.setDomain(config.getConfig().getHttpConfig().getDomain());
sampler.setPort(config.getConfig().getHttpConfig().getPort());
sampler.setProtocol(config.getConfig().getHttpConfig().getProtocol());
url = config.getConfig().getHttpConfig().getProtocol() + "://" + config.getConfig().getHttpConfig().getSocket();
URL urlObject = new URL(url);
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
if (StringUtils.isNotBlank(this.getPath())) {
envPath += this.getPath();
}
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
sampler.setPath(getRestParameters(URLDecoder.decode(envPath, "UTF-8")));
} else {
envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8"));
sampler.setPath(envPath);
}
if (CollectionUtils.isNotEmpty(this.getArguments())) {
sampler.setPath(getPostQueryParameters(URLDecoder.decode(envPath, "UTF-8")));
}
} else {
@ -125,18 +135,24 @@ public class MsHTTPSamplerProxy extends MsTestElement {
sampler.setPort(urlObject.getPort());
sampler.setProtocol(urlObject.getProtocol());
sampler.setPath(getRestParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
sampler.setPath(getPostQueryParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
sampler.setPath(getRestParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
}
if (CollectionUtils.isNotEmpty(this.getArguments())) {
sampler.setPath(getPostQueryParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
}
}
} catch (Exception e) {
LogUtil.error(e);
}
// REST参数
if (CollectionUtils.isNotEmpty(this.getArguments())) {
sampler.setArguments(httpArguments(this.getRest()));
}
// 请求参数
if (CollectionUtils.isNotEmpty(this.getArguments())) {
sampler.setArguments(httpArguments(this.getArguments()));
}
// 请求体
if (!StringUtils.equals(this.getMethod(), "GET")) {
List<KeyValue> bodyParams = this.body.getBodyParams(sampler, this.getId());
@ -148,9 +164,10 @@ public class MsHTTPSamplerProxy extends MsTestElement {
setHeader(httpSamplerTree);
}
//判断是否要开启DNS
if (config != null && config.getCommonConfig() != null && config.getCommonConfig().isEnableHost()) {
MsDNSCacheManager.addEnvironmentVariables(httpSamplerTree, this.getName(), config);
MsDNSCacheManager.addEnvironmentDNS(httpSamplerTree, this.getName(), config);
if (config != null && config.getConfig() != null && config.getConfig().getCommonConfig() != null
&& config.getConfig().getCommonConfig().isEnableHost()) {
MsDNSCacheManager.addEnvironmentVariables(httpSamplerTree, this.getName(), config.getConfig());
MsDNSCacheManager.addEnvironmentDNS(httpSamplerTree, this.getName(), config.getConfig());
}
if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) {
@ -163,10 +180,22 @@ public class MsHTTPSamplerProxy extends MsTestElement {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(path);
stringBuffer.append("/");
Map<String, String> keyValueMap = new HashMap<>();
this.getRest().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).forEach(keyValue ->
stringBuffer.append(keyValue.getValue()).append("/")
keyValueMap.put(keyValue.getName(), keyValue.getValue())
);
return stringBuffer.substring(0, stringBuffer.length() - 1);
Pattern p = Pattern.compile("(\\{)([\\w]+)(\\})");
Matcher m = p.matcher(path);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String group = m.group(2);
//替换并且把替换好的值放到sb中
m.appendReplacement(sb, keyValueMap.get(group));
}
//把符合的数据追加到sb尾
m.appendTail(sb);
return sb.toString();
}
private String getPostQueryParameters(String path) {
@ -209,4 +238,5 @@ public class MsHTTPSamplerProxy extends MsTestElement {
private boolean isRest() {
return this.getRest().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).toArray().length > 0;
}
}

View File

@ -3,9 +3,9 @@ package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.DatabaseConfig;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -39,7 +39,10 @@ public class MsJDBCSampler extends MsTestElement {
@JSONField(ordinal = 16)
private String environmentId;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
this.getRefElement(this);
}
final HashTree samplerHashTree = tree.add(jdbcSampler());
tree.add(jdbcDataSource());
tree.add(arguments(this.getName() + " Variables", this.getVariables()));

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -49,7 +49,10 @@ public class MsTCPSampler extends MsTestElement {
@JSONField(ordinal = 23)
private String request;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
this.getRefElement(this);
}
final HashTree samplerHashTree = new ListedHashTree();
samplerHashTree.add(tcpConfig());
tree.set(tcpSampler(), samplerHashTree);

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.timer;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -26,7 +26,7 @@ public class MsConstantTimer extends MsTestElement {
@JSONField(ordinal = 12)
private String delay;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
final HashTree groupTree = tree.add(constantTimer());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {

View File

@ -229,7 +229,11 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
if (StringUtils.equals("Error", report.getStatus())) {
event = NoticeConstants.Event.EXECUTE_FAILED;
}
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("testName", report.getName());
paramMap.put("id", report.getId());
paramMap.put("type", "performance");
paramMap.put("url", baseSystemConfigDTO.getUrl());
NoticeModel noticeModel = NoticeModel.builder()
.successContext(successContext)
.successMailTemplate("ApiSuccessfulNotification")
@ -239,6 +243,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
.status(report.getStatus())
.event(event)
.subject(subject)
.paramMap(paramMap)
.build();
noticeSendService.send(report.getTriggerMode(), noticeModel);
}

View File

@ -9,38 +9,38 @@ import com.google.gson.Gson;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.definition.request.*;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiTagMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.track.dto.TestPlanDTO;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Service
@Transactional(rollbackFor = Exception.class)
@ -48,6 +48,8 @@ public class ApiAutomationService {
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private ApiTagMapper apiTagMapper;
@ -57,6 +59,10 @@ public class ApiAutomationService {
private ApiTestEnvironmentService environmentService;
@Resource
private ApiScenarioReportService apiReportService;
@Resource
private ExtTestPlanMapper extTestPlanMapper;
@Resource
SqlSessionFactory sqlSessionFactory;
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
@ -119,13 +125,13 @@ public class ApiAutomationService {
apiScenarioMapper.insert(scenario);
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(bodyUploadIds, bodyFiles);
apiDefinitionService.createBodyFiles(bodyUploadIds, bodyFiles);
}
public void update(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles) {
checkNameExist(request);
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(bodyUploadIds, bodyFiles);
List<String> bodyUploadIds = request.getBodyUploadIds();
apiDefinitionService.createBodyFiles(bodyUploadIds, bodyFiles);
final ApiScenario scenario = new ApiScenario();
scenario.setId(request.getId());
@ -170,7 +176,7 @@ public class ApiAutomationService {
private void checkNameExist(SaveApiScenarioRequest request) {
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andStatusNotEqualTo("Trash").andIdNotEqualTo(request.getId());
if (apiScenarioMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("automation_name_already_exists"));
}
@ -187,26 +193,6 @@ public class ApiAutomationService {
return new ArrayList<>();
}
private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (!bodyUploadIds.isEmpty() && !bodyFiles.isEmpty()) {
File testDir = new File(BODY_FILE_DIR);
if (!testDir.exists()) {
testDir.mkdirs();
}
for (int i = 0; i < bodyUploadIds.size(); i++) {
MultipartFile item = bodyFiles.get(i);
File file = new File(BODY_FILE_DIR + "/" + bodyUploadIds.get(i) + "_" + item.getOriginalFilename());
try (InputStream in = item.getInputStream(); OutputStream out = new FileOutputStream(file)) {
file.createNewFile();
FileUtil.copyStream(in, out);
} catch (IOException e) {
LogUtil.error(e);
MSException.throwException(Translator.get("upload_fail"));
}
}
}
}
public void deleteTag(String id) {
List<ApiScenario> list = extApiScenarioMapper.selectByTagId(id);
if (!list.isEmpty()) {
@ -220,7 +206,7 @@ public class ApiAutomationService {
}
}
private void createAPIReportResult(String id) {
private void createAPIReportResult(String id, String triggerMode) {
APIReportResult report = new APIReportResult();
report.setId(id);
report.setTestId(id);
@ -230,6 +216,7 @@ public class ApiAutomationService {
report.setUpdateTime(System.currentTimeMillis());
report.setStatus(APITestStatus.Running.name());
report.setUserId(SessionUtils.getUserId());
report.setTriggerMode(triggerMode);
apiReportService.addResult(report);
}
@ -245,7 +232,6 @@ public class ApiAutomationService {
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
HashTree jmeterTestPlanHashTree = new ListedHashTree();
EnvironmentConfig config = null;
for (ApiScenario item : apiScenarios) {
MsThreadGroup group = new MsThreadGroup();
group.setLabel(item.getName());
@ -254,25 +240,27 @@ public class ApiAutomationService {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JSONObject element = JSON.parseObject(item.getScenarioDefinition());
String environmentId = element.getString("environmentId");
if (environmentId != null) {
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
}
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
group.setHashTree(elements);
MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class);
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {});
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
new TypeReference<LinkedList<KeyValue>>() {});
scenario.setHashTree(elements);
scenario.setVariables(variables);
LinkedList<MsTestElement> scenarios = new LinkedList<>();
scenarios.add(scenario);
group.setHashTree(scenarios);
testPlan.getHashTree().add(group);
} catch (Exception ex) {
ex.printStackTrace();
}
}
testPlan.toHashTree(jmeterTestPlanHashTree, testPlan.getHashTree(), config);
testPlan.toHashTree(jmeterTestPlanHashTree, testPlan.getHashTree(), new ParameterConfig());
// 调用执行方法
jMeterService.runDefinition(request.getId(), jmeterTestPlanHashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
createAPIReportResult(request.getId());
createAPIReportResult(request.getId(), request.getTriggerMode() == null ? ReportTriggerMode.API.name() : request.getTriggerMode());
return request.getId();
}
@ -286,22 +274,71 @@ public class ApiAutomationService {
*/
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(bodyUploadIds, bodyFiles);
EnvironmentConfig config = null;
apiDefinitionService.createBodyFiles(bodyUploadIds, bodyFiles);
EnvironmentConfig envConfig = null;
if (request.getEnvironmentId() != null) {
ApiTestEnvironmentWithBLOBs environment = environmentService.get(request.getEnvironmentId());
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
envConfig = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
}
ParameterConfig config = new ParameterConfig();
config.setConfig(envConfig);
HashTree hashTree = request.getTestElement().generateHashTree(config);
request.getTestElement().getJmx(hashTree);
// 调用执行方法
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
createAPIReportResult(request.getId());
createAPIReportResult(request.getId(), ReportTriggerMode.MANUAL.name());
return request.getId();
}
public List<ApiScenario> getReference(ApiScenarioRequest request) {
return extApiScenarioMapper.selectReference(request);
public ReferenceDTO getReference(ApiScenarioRequest request) {
ReferenceDTO dto = new ReferenceDTO();
dto.setScenarioList(extApiScenarioMapper.selectReference(request));
QueryTestPlanRequest planRequest = new QueryTestPlanRequest();
planRequest.setScenarioId(request.getId());
planRequest.setProjectId(request.getProjectId());
dto.setTestPlanList(extTestPlanMapper.selectReference(planRequest));
return dto;
}
public String addScenarioToPlan(SaveApiPlanRequest request) {
if (CollectionUtils.isEmpty(request.getPlanIds())) {
MSException.throwException(Translator.get("plan id is null "));
}
List<TestPlanDTO> list = extTestPlanMapper.selectByIds(request.getPlanIds());
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ExtTestPlanMapper mapper = sqlSession.getMapper(ExtTestPlanMapper.class);
list.forEach(item -> {
if (CollectionUtils.isNotEmpty(request.getApiIds())) {
if (CollectionUtils.isNotEmpty(request.getApiIds())) {
if (StringUtils.isEmpty(item.getApiIds())) {
item.setApiIds(JSON.toJSONString(request.getApiIds()));
} else {
// 合并api
List<String> dbApiIDs = JSON.parseArray(item.getApiIds(), String.class);
List<String> result = Stream.of(request.getApiIds(), dbApiIDs)
.flatMap(Collection::stream).distinct().collect(Collectors.toList());
item.setApiIds(JSON.toJSONString(result));
}
item.setScenarioIds(null);
}
}
if (CollectionUtils.isNotEmpty(request.getScenarioIds())) {
if (CollectionUtils.isNotEmpty(request.getScenarioIds())) {
if (StringUtils.isEmpty(item.getScenarioIds())) {
item.setScenarioIds(JSON.toJSONString(request.getScenarioIds()));
} else {
// 合并场景ID
List<String> dbScenarioIDs = JSON.parseArray(item.getScenarioIds(), String.class);
List<String> result = Stream.of(request.getScenarioIds(), dbScenarioIDs)
.flatMap(Collection::stream).distinct().collect(Collectors.toList());
item.setScenarioIds(JSON.toJSONString(result));
}
item.setApiIds(null);
}
}
mapper.updatePlan(item);
});
sqlSession.flushStatements();
return "success";
}
}

View File

@ -4,6 +4,8 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.ReferenceDTO;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.scenario.request.RequestType;
@ -16,6 +18,8 @@ import io.metersphere.base.mapper.ApiDefinitionMapper;
import io.metersphere.base.mapper.ApiTestFileMapper;
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ext.ExtApiDefinitionMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.exception.MSException;
@ -25,7 +29,8 @@ import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.service.FileService;
import org.apache.commons.lang3.StringUtils;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
@ -33,13 +38,15 @@ import org.apache.jorphan.collections.HashTree;
import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.security.util.Cache;
import javax.annotation.Resource;
import java.io.*;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -63,7 +70,9 @@ public class ApiDefinitionService {
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ApiModuleService apiModuleService;
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private ExtTestPlanMapper extTestPlanMapper;
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24);
@ -96,6 +105,10 @@ public class ApiDefinitionService {
return apiDefinitionMapper.selectByPrimaryKey(id);
}
public ApiDefinitionWithBLOBs getBLOBs(String id) {
return apiDefinitionMapper.selectByPrimaryKey(id);
}
public void create(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createTest(request);
@ -103,15 +116,17 @@ public class ApiDefinitionService {
}
public void update(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
deleteFileByTestId(request.getRequest().getId());
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
if (request.getRequest() != null) {
deleteFileByTestId(request.getRequest().getId());
}
List<String> bodyUploadIds = request.getBodyUploadIds();
request.setBodyUploadIds(null);
updateTest(request);
createBodyFiles(bodyUploadIds, bodyFiles);
}
private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (bodyUploadIds.size() > 0) {
public void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (CollectionUtils.isNotEmpty(bodyUploadIds) && CollectionUtils.isNotEmpty(bodyFiles)) {
File testDir = new File(BODY_FILE_DIR);
if (!testDir.exists()) {
testDir.mkdirs();
@ -139,10 +154,9 @@ public class ApiDefinitionService {
}
public void deleteBatch(List<String> apiIds) {
// 简单处理后续优化
apiIds.forEach(item -> {
delete(item);
});
ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria().andIdIn(apiIds);
apiDefinitionMapper.deleteByExample(example);
}
public void removeToGc(List<String> apiIds) {
@ -160,14 +174,14 @@ public class ApiDefinitionService {
private void checkNameExist(SaveApiDefinitionRequest request) {
ApiDefinitionExample example = new ApiDefinitionExample();
if (request.getProtocol().equals(RequestType.HTTP)) {
example.createCriteria().andMethodEqualTo(request.getMethod())
example.createCriteria().andMethodEqualTo(request.getMethod()).andStatusNotEqualTo("Trash")
.andProtocolEqualTo(request.getProtocol()).andPathEqualTo(request.getPath())
.andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
if (apiDefinitionMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("api_definition_url_not_repeating"));
}
} else {
example.createCriteria().andProtocolEqualTo(request.getProtocol())
example.createCriteria().andProtocolEqualTo(request.getProtocol()).andStatusNotEqualTo("Trash")
.andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId())
.andIdNotEqualTo(request.getId());
if (apiDefinitionMapper.countByExample(example) > 0) {
@ -176,7 +190,6 @@ public class ApiDefinitionService {
}
}
private ApiDefinition updateTest(SaveApiDefinitionRequest request) {
checkNameExist(request);
final ApiDefinitionWithBLOBs test = new ApiDefinitionWithBLOBs();
@ -349,4 +362,13 @@ public class ApiDefinitionService {
sqlSession.flushStatements();
}
public ReferenceDTO getReference(ApiScenarioRequest request) {
ReferenceDTO dto = new ReferenceDTO();
dto.setScenarioList(extApiScenarioMapper.selectReference(request));
QueryTestPlanRequest planRequest = new QueryTestPlanRequest();
planRequest.setApiId(request.getId());
planRequest.setProjectId(request.getProjectId());
dto.setTestPlanList(extTestPlanMapper.selectReference(planRequest));
return dto;
}
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.DeleteAPIReportRequest;
@ -7,6 +8,7 @@ import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioReportDetailMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper;
@ -21,6 +23,7 @@ import sun.security.util.Cache;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.List;
import java.util.UUID;
@ -35,6 +38,8 @@ public class ApiScenarioReportService {
private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
private ApiScenarioReportDetailMapper apiScenarioReportDetailMapper;
@Resource
private ApiScenarioMapper apiScenarioMapper;
public void complete(TestResult result) {
Object obj = cache.get(result.getTestId());
@ -139,6 +144,27 @@ public class ApiScenarioReportService {
public String add(APIScenarioReportResult test) {
ApiScenarioReport report = createReport(test);
ApiScenarioReportDetail detail = new ApiScenarioReportDetail();
TestResult result = JSON.parseObject(test.getContent(), TestResult.class);
// 更新场景
if (result != null) {
result.getScenarios().forEach(item -> {
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andNameEqualTo(item.getName()).andProjectIdEqualTo(test.getProjectId());
List<ApiScenario> list = apiScenarioMapper.selectByExample(example);
if (list.size() > 0) {
ApiScenario scenario = list.get(0);
if (item.getError() > 0) {
scenario.setLastResult("Fail");
} else {
scenario.setLastResult("Success");
}
String passRate = new DecimalFormat("0%").format((float) item.getSuccess() / (item.getSuccess() + item.getError()));
scenario.setPassRate(passRate);
scenario.setReportId(report.getId());
apiScenarioMapper.updateByPrimaryKey(scenario);
}
});
}
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
detail.setReportId(report.getId());
detail.setProjectId(test.getProjectId());

View File

@ -37,6 +37,12 @@ public class ApiScenario implements Serializable {
private Long updateTime;
private String passRate;
private String lastResult;
private String reportId;
private String scenarioDefinition;
private static final long serialVersionUID = 1L;

View File

@ -1193,6 +1193,216 @@ public class ApiScenarioExample {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andPassRateIsNull() {
addCriterion("pass_rate is null");
return (Criteria) this;
}
public Criteria andPassRateIsNotNull() {
addCriterion("pass_rate is not null");
return (Criteria) this;
}
public Criteria andPassRateEqualTo(String value) {
addCriterion("pass_rate =", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateNotEqualTo(String value) {
addCriterion("pass_rate <>", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateGreaterThan(String value) {
addCriterion("pass_rate >", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateGreaterThanOrEqualTo(String value) {
addCriterion("pass_rate >=", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateLessThan(String value) {
addCriterion("pass_rate <", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateLessThanOrEqualTo(String value) {
addCriterion("pass_rate <=", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateLike(String value) {
addCriterion("pass_rate like", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateNotLike(String value) {
addCriterion("pass_rate not like", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateIn(List<String> values) {
addCriterion("pass_rate in", values, "passRate");
return (Criteria) this;
}
public Criteria andPassRateNotIn(List<String> values) {
addCriterion("pass_rate not in", values, "passRate");
return (Criteria) this;
}
public Criteria andPassRateBetween(String value1, String value2) {
addCriterion("pass_rate between", value1, value2, "passRate");
return (Criteria) this;
}
public Criteria andPassRateNotBetween(String value1, String value2) {
addCriterion("pass_rate not between", value1, value2, "passRate");
return (Criteria) this;
}
public Criteria andLastResultIsNull() {
addCriterion("last_result is null");
return (Criteria) this;
}
public Criteria andLastResultIsNotNull() {
addCriterion("last_result is not null");
return (Criteria) this;
}
public Criteria andLastResultEqualTo(String value) {
addCriterion("last_result =", value, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultNotEqualTo(String value) {
addCriterion("last_result <>", value, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultGreaterThan(String value) {
addCriterion("last_result >", value, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultGreaterThanOrEqualTo(String value) {
addCriterion("last_result >=", value, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultLessThan(String value) {
addCriterion("last_result <", value, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultLessThanOrEqualTo(String value) {
addCriterion("last_result <=", value, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultLike(String value) {
addCriterion("last_result like", value, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultNotLike(String value) {
addCriterion("last_result not like", value, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultIn(List<String> values) {
addCriterion("last_result in", values, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultNotIn(List<String> values) {
addCriterion("last_result not in", values, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultBetween(String value1, String value2) {
addCriterion("last_result between", value1, value2, "lastResult");
return (Criteria) this;
}
public Criteria andLastResultNotBetween(String value1, String value2) {
addCriterion("last_result not between", value1, value2, "lastResult");
return (Criteria) this;
}
public Criteria andReportIdIsNull() {
addCriterion("report_id is null");
return (Criteria) this;
}
public Criteria andReportIdIsNotNull() {
addCriterion("report_id is not null");
return (Criteria) this;
}
public Criteria andReportIdEqualTo(String value) {
addCriterion("report_id =", value, "reportId");
return (Criteria) this;
}
public Criteria andReportIdNotEqualTo(String value) {
addCriterion("report_id <>", value, "reportId");
return (Criteria) this;
}
public Criteria andReportIdGreaterThan(String value) {
addCriterion("report_id >", value, "reportId");
return (Criteria) this;
}
public Criteria andReportIdGreaterThanOrEqualTo(String value) {
addCriterion("report_id >=", value, "reportId");
return (Criteria) this;
}
public Criteria andReportIdLessThan(String value) {
addCriterion("report_id <", value, "reportId");
return (Criteria) this;
}
public Criteria andReportIdLessThanOrEqualTo(String value) {
addCriterion("report_id <=", value, "reportId");
return (Criteria) this;
}
public Criteria andReportIdLike(String value) {
addCriterion("report_id like", value, "reportId");
return (Criteria) this;
}
public Criteria andReportIdNotLike(String value) {
addCriterion("report_id not like", value, "reportId");
return (Criteria) this;
}
public Criteria andReportIdIn(List<String> values) {
addCriterion("report_id in", values, "reportId");
return (Criteria) this;
}
public Criteria andReportIdNotIn(List<String> values) {
addCriterion("report_id not in", values, "reportId");
return (Criteria) this;
}
public Criteria andReportIdBetween(String value1, String value2) {
addCriterion("report_id between", value1, value2, "reportId");
return (Criteria) this;
}
public Criteria andReportIdNotBetween(String value1, String value2) {
addCriterion("report_id not between", value1, value2, "reportId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -1,8 +1,7 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
import lombok.Data;
@Data
public class ApiScenarioReport implements Serializable {

View File

@ -1,8 +1,9 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
import java.io.Serializable;
@Data
public class TestPlan implements Serializable {
private String id;
@ -39,6 +40,10 @@ public class TestPlan implements Serializable {
private String creator;
private String apiIds;
private String scenarioIds;
private String tags;
private static final long serialVersionUID = 1L;

View File

@ -1233,6 +1233,146 @@ public class TestPlanExample {
addCriterion("creator not between", value1, value2, "creator");
return (Criteria) this;
}
public Criteria andApiIdsIsNull() {
addCriterion("api_ids is null");
return (Criteria) this;
}
public Criteria andApiIdsIsNotNull() {
addCriterion("api_ids is not null");
return (Criteria) this;
}
public Criteria andApiIdsEqualTo(String value) {
addCriterion("api_ids =", value, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsNotEqualTo(String value) {
addCriterion("api_ids <>", value, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsGreaterThan(String value) {
addCriterion("api_ids >", value, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsGreaterThanOrEqualTo(String value) {
addCriterion("api_ids >=", value, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsLessThan(String value) {
addCriterion("api_ids <", value, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsLessThanOrEqualTo(String value) {
addCriterion("api_ids <=", value, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsLike(String value) {
addCriterion("api_ids like", value, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsNotLike(String value) {
addCriterion("api_ids not like", value, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsIn(List<String> values) {
addCriterion("api_ids in", values, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsNotIn(List<String> values) {
addCriterion("api_ids not in", values, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsBetween(String value1, String value2) {
addCriterion("api_ids between", value1, value2, "apiIds");
return (Criteria) this;
}
public Criteria andApiIdsNotBetween(String value1, String value2) {
addCriterion("api_ids not between", value1, value2, "apiIds");
return (Criteria) this;
}
public Criteria andScenarioIdsIsNull() {
addCriterion("scenario_ids is null");
return (Criteria) this;
}
public Criteria andScenarioIdsIsNotNull() {
addCriterion("scenario_ids is not null");
return (Criteria) this;
}
public Criteria andScenarioIdsEqualTo(String value) {
addCriterion("scenario_ids =", value, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsNotEqualTo(String value) {
addCriterion("scenario_ids <>", value, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsGreaterThan(String value) {
addCriterion("scenario_ids >", value, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsGreaterThanOrEqualTo(String value) {
addCriterion("scenario_ids >=", value, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsLessThan(String value) {
addCriterion("scenario_ids <", value, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsLessThanOrEqualTo(String value) {
addCriterion("scenario_ids <=", value, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsLike(String value) {
addCriterion("scenario_ids like", value, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsNotLike(String value) {
addCriterion("scenario_ids not like", value, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsIn(List<String> values) {
addCriterion("scenario_ids in", values, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsNotIn(List<String> values) {
addCriterion("scenario_ids not in", values, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsBetween(String value1, String value2) {
addCriterion("scenario_ids between", value1, value2, "scenarioIds");
return (Criteria) this;
}
public Criteria andScenarioIdsNotBetween(String value1, String value2) {
addCriterion("scenario_ids not between", value1, value2, "scenarioIds");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -29,5 +29,7 @@ public class User implements Serializable {
private String source;
private String lastProjectId;
private static final long serialVersionUID = 1L;
}

View File

@ -923,6 +923,76 @@ public class UserExample {
addCriterion("`source` not between", value1, value2, "source");
return (Criteria) this;
}
public Criteria andLastProjectIdIsNull() {
addCriterion("last_project_id is null");
return (Criteria) this;
}
public Criteria andLastProjectIdIsNotNull() {
addCriterion("last_project_id is not null");
return (Criteria) this;
}
public Criteria andLastProjectIdEqualTo(String value) {
addCriterion("last_project_id =", value, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdNotEqualTo(String value) {
addCriterion("last_project_id <>", value, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdGreaterThan(String value) {
addCriterion("last_project_id >", value, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("last_project_id >=", value, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdLessThan(String value) {
addCriterion("last_project_id <", value, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdLessThanOrEqualTo(String value) {
addCriterion("last_project_id <=", value, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdLike(String value) {
addCriterion("last_project_id like", value, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdNotLike(String value) {
addCriterion("last_project_id not like", value, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdIn(List<String> values) {
addCriterion("last_project_id in", values, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdNotIn(List<String> values) {
addCriterion("last_project_id not in", values, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdBetween(String value1, String value2) {
addCriterion("last_project_id between", value1, value2, "lastProjectId");
return (Criteria) this;
}
public Criteria andLastProjectIdNotBetween(String value1, String value2) {
addCriterion("last_project_id not between", value1, value2, "lastProjectId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -18,6 +18,9 @@
<result column="description" jdbcType="VARCHAR" property="description" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="pass_rate" jdbcType="VARCHAR" property="passRate" />
<result column="last_result" jdbcType="VARCHAR" property="lastResult" />
<result column="report_id" jdbcType="VARCHAR" property="reportId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenario">
<result column="scenario_definition" jdbcType="LONGVARCHAR" property="scenarioDefinition" />
@ -83,7 +86,7 @@
<sql id="Base_Column_List">
id, project_id, tag_id, user_id, api_scenario_module_id, module_path, `name`, `level`,
`status`, principal, step_total, follow_people, schedule, description, create_time,
update_time
update_time, pass_rate, last_result, report_id
</sql>
<sql id="Blob_Column_List">
scenario_definition
@ -142,13 +145,15 @@
`name`, `level`, `status`,
principal, step_total, follow_people,
schedule, description, create_time,
update_time, scenario_definition)
update_time, pass_rate, last_result,
report_id, scenario_definition)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{tagId,jdbcType=VARCHAR},
#{userId,jdbcType=VARCHAR}, #{apiScenarioModuleId,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{level,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{principal,jdbcType=VARCHAR}, #{stepTotal,jdbcType=INTEGER}, #{followPeople,jdbcType=VARCHAR},
#{schedule,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{scenarioDefinition,jdbcType=LONGVARCHAR})
#{updateTime,jdbcType=BIGINT}, #{passRate,jdbcType=VARCHAR}, #{lastResult,jdbcType=VARCHAR},
#{reportId,jdbcType=VARCHAR}, #{scenarioDefinition,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenario">
insert into api_scenario
@ -201,6 +206,15 @@
<if test="updateTime != null">
update_time,
</if>
<if test="passRate != null">
pass_rate,
</if>
<if test="lastResult != null">
last_result,
</if>
<if test="reportId != null">
report_id,
</if>
<if test="scenarioDefinition != null">
scenario_definition,
</if>
@ -254,6 +268,15 @@
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="passRate != null">
#{passRate,jdbcType=VARCHAR},
</if>
<if test="lastResult != null">
#{lastResult,jdbcType=VARCHAR},
</if>
<if test="reportId != null">
#{reportId,jdbcType=VARCHAR},
</if>
<if test="scenarioDefinition != null">
#{scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
@ -316,6 +339,15 @@
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.passRate != null">
pass_rate = #{record.passRate,jdbcType=VARCHAR},
</if>
<if test="record.lastResult != null">
last_result = #{record.lastResult,jdbcType=VARCHAR},
</if>
<if test="record.reportId != null">
report_id = #{record.reportId,jdbcType=VARCHAR},
</if>
<if test="record.scenarioDefinition != null">
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
@ -342,6 +374,9 @@
description = #{record.description,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pass_rate = #{record.passRate,jdbcType=VARCHAR},
last_result = #{record.lastResult,jdbcType=VARCHAR},
report_id = #{record.reportId,jdbcType=VARCHAR},
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -364,7 +399,10 @@
schedule = #{record.schedule,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}
update_time = #{record.updateTime,jdbcType=BIGINT},
pass_rate = #{record.passRate,jdbcType=VARCHAR},
last_result = #{record.lastResult,jdbcType=VARCHAR},
report_id = #{record.reportId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -417,6 +455,15 @@
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="passRate != null">
pass_rate = #{passRate,jdbcType=VARCHAR},
</if>
<if test="lastResult != null">
last_result = #{lastResult,jdbcType=VARCHAR},
</if>
<if test="reportId != null">
report_id = #{reportId,jdbcType=VARCHAR},
</if>
<if test="scenarioDefinition != null">
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
@ -440,6 +487,9 @@
description = #{description,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pass_rate = #{passRate,jdbcType=VARCHAR},
last_result = #{lastResult,jdbcType=VARCHAR},
report_id = #{reportId,jdbcType=VARCHAR},
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -459,7 +509,10 @@
schedule = #{schedule,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}
update_time = #{updateTime,jdbcType=BIGINT},
pass_rate = #{passRate,jdbcType=VARCHAR},
last_result = #{lastResult,jdbcType=VARCHAR},
report_id = #{reportId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -19,6 +19,8 @@
<result column="planned_end_time" jdbcType="BIGINT" property="plannedEndTime" />
<result column="actual_start_time" jdbcType="BIGINT" property="actualStartTime" />
<result column="creator" jdbcType="VARCHAR" property="creator" />
<result column="api_ids" jdbcType="VARCHAR" property="apiIds" />
<result column="scenario_ids" jdbcType="VARCHAR" property="scenarioIds" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestPlan">
<result column="tags" jdbcType="LONGVARCHAR" property="tags" />
@ -84,7 +86,7 @@
<sql id="Base_Column_List">
id, workspace_id, report_id, `name`, description, `status`, stage, principal, test_case_match_rule,
executor_match_rule, create_time, update_time, actual_end_time, planned_start_time,
planned_end_time, actual_start_time, creator
planned_end_time, actual_start_time, creator, api_ids, scenario_ids
</sql>
<sql id="Blob_Column_List">
tags
@ -143,15 +145,15 @@
stage, principal, test_case_match_rule,
executor_match_rule, create_time, update_time,
actual_end_time, planned_start_time, planned_end_time,
actual_start_time, creator, tags
)
actual_start_time, creator, api_ids,
scenario_ids, tags)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{stage,jdbcType=VARCHAR}, #{principal,jdbcType=VARCHAR}, #{testCaseMatchRule,jdbcType=VARCHAR},
#{executorMatchRule,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{actualEndTime,jdbcType=BIGINT}, #{plannedStartTime,jdbcType=BIGINT}, #{plannedEndTime,jdbcType=BIGINT},
#{actualStartTime,jdbcType=BIGINT}, #{creator,jdbcType=VARCHAR}, #{tags,jdbcType=LONGVARCHAR}
)
#{actualStartTime,jdbcType=BIGINT}, #{creator,jdbcType=VARCHAR}, #{apiIds,jdbcType=VARCHAR},
#{scenarioIds,jdbcType=VARCHAR}, #{tags,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlan">
insert into test_plan
@ -207,6 +209,12 @@
<if test="creator != null">
creator,
</if>
<if test="apiIds != null">
api_ids,
</if>
<if test="scenarioIds != null">
scenario_ids,
</if>
<if test="tags != null">
tags,
</if>
@ -263,6 +271,12 @@
<if test="creator != null">
#{creator,jdbcType=VARCHAR},
</if>
<if test="apiIds != null">
#{apiIds,jdbcType=VARCHAR},
</if>
<if test="scenarioIds != null">
#{scenarioIds,jdbcType=VARCHAR},
</if>
<if test="tags != null">
#{tags,jdbcType=LONGVARCHAR},
</if>
@ -328,6 +342,12 @@
<if test="record.creator != null">
creator = #{record.creator,jdbcType=VARCHAR},
</if>
<if test="record.apiIds != null">
api_ids = #{record.apiIds,jdbcType=VARCHAR},
</if>
<if test="record.scenarioIds != null">
scenario_ids = #{record.scenarioIds,jdbcType=VARCHAR},
</if>
<if test="record.tags != null">
tags = #{record.tags,jdbcType=LONGVARCHAR},
</if>
@ -355,6 +375,8 @@
planned_end_time = #{record.plannedEndTime,jdbcType=BIGINT},
actual_start_time = #{record.actualStartTime,jdbcType=BIGINT},
creator = #{record.creator,jdbcType=VARCHAR},
api_ids = #{record.apiIds,jdbcType=VARCHAR},
scenario_ids = #{record.scenarioIds,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -378,7 +400,9 @@
planned_start_time = #{record.plannedStartTime,jdbcType=BIGINT},
planned_end_time = #{record.plannedEndTime,jdbcType=BIGINT},
actual_start_time = #{record.actualStartTime,jdbcType=BIGINT},
creator = #{record.creator,jdbcType=VARCHAR}
creator = #{record.creator,jdbcType=VARCHAR},
api_ids = #{record.apiIds,jdbcType=VARCHAR},
scenario_ids = #{record.scenarioIds,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -434,6 +458,12 @@
<if test="creator != null">
creator = #{creator,jdbcType=VARCHAR},
</if>
<if test="apiIds != null">
api_ids = #{apiIds,jdbcType=VARCHAR},
</if>
<if test="scenarioIds != null">
scenario_ids = #{scenarioIds,jdbcType=VARCHAR},
</if>
<if test="tags != null">
tags = #{tags,jdbcType=LONGVARCHAR},
</if>
@ -458,6 +488,8 @@
planned_end_time = #{plannedEndTime,jdbcType=BIGINT},
actual_start_time = #{actualStartTime,jdbcType=BIGINT},
creator = #{creator,jdbcType=VARCHAR},
api_ids = #{apiIds,jdbcType=VARCHAR},
scenario_ids = #{scenarioIds,jdbcType=VARCHAR},
tags = #{tags,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -478,7 +510,9 @@
planned_start_time = #{plannedStartTime,jdbcType=BIGINT},
planned_end_time = #{plannedEndTime,jdbcType=BIGINT},
actual_start_time = #{actualStartTime,jdbcType=BIGINT},
creator = #{creator,jdbcType=VARCHAR}
creator = #{creator,jdbcType=VARCHAR},
api_ids = #{apiIds,jdbcType=VARCHAR},
scenario_ids = #{scenarioIds,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -14,6 +14,7 @@
<result column="last_organization_id" jdbcType="VARCHAR" property="lastOrganizationId" />
<result column="phone" jdbcType="VARCHAR" property="phone" />
<result column="source" jdbcType="VARCHAR" property="source" />
<result column="last_project_id" jdbcType="VARCHAR" property="lastProjectId" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -75,7 +76,7 @@
</sql>
<sql id="Base_Column_List">
id, `name`, email, `password`, `status`, create_time, update_time, `language`, last_workspace_id,
last_organization_id, phone, `source`
last_organization_id, phone, `source`, last_project_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.UserExample" resultMap="BaseResultMap">
select
@ -111,13 +112,13 @@
insert into user (id, `name`, email,
`password`, `status`, create_time,
update_time, `language`, last_workspace_id,
last_organization_id, phone, `source`
)
last_organization_id, phone, `source`,
last_project_id)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{language,jdbcType=VARCHAR}, #{lastWorkspaceId,jdbcType=VARCHAR},
#{lastOrganizationId,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, #{source,jdbcType=VARCHAR}
)
#{lastOrganizationId,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, #{source,jdbcType=VARCHAR},
#{lastProjectId,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.User">
insert into user
@ -158,6 +159,9 @@
<if test="source != null">
`source`,
</if>
<if test="lastProjectId != null">
last_project_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -196,6 +200,9 @@
<if test="source != null">
#{source,jdbcType=VARCHAR},
</if>
<if test="lastProjectId != null">
#{lastProjectId,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.UserExample" resultType="java.lang.Long">
@ -243,6 +250,9 @@
<if test="record.source != null">
`source` = #{record.source,jdbcType=VARCHAR},
</if>
<if test="record.lastProjectId != null">
last_project_id = #{record.lastProjectId,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -261,7 +271,8 @@
last_workspace_id = #{record.lastWorkspaceId,jdbcType=VARCHAR},
last_organization_id = #{record.lastOrganizationId,jdbcType=VARCHAR},
phone = #{record.phone,jdbcType=VARCHAR},
`source` = #{record.source,jdbcType=VARCHAR}
`source` = #{record.source,jdbcType=VARCHAR},
last_project_id = #{record.lastProjectId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -302,6 +313,9 @@
<if test="source != null">
`source` = #{source,jdbcType=VARCHAR},
</if>
<if test="lastProjectId != null">
last_project_id = #{lastProjectId,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
@ -317,7 +331,8 @@
last_workspace_id = #{lastWorkspaceId,jdbcType=VARCHAR},
last_organization_id = #{lastOrganizationId,jdbcType=VARCHAR},
phone = #{phone,jdbcType=VARCHAR},
`source` = #{source,jdbcType=VARCHAR}
`source` = #{source,jdbcType=VARCHAR},
last_project_id = #{lastProjectId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -12,6 +12,7 @@
select api_scenario.id, api_scenario.project_id, api_scenario.tag_id, api_scenario.user_id,
api_scenario.api_scenario_module_id,api_scenario.module_path, api_scenario.name, api_scenario.level,
api_scenario.status, api_scenario.principal, api_scenario.step_total, api_scenario.follow_people,
api_scenario.last_result,api_scenario.pass_rate,api_scenario.report_id,
api_scenario.schedule, api_scenario.description, api_scenario.create_time, api_scenario.update_time,
project.name as project_name, user.name as user_name
from api_scenario
@ -74,7 +75,6 @@
<select id="selectReference" resultType="io.metersphere.base.domain.ApiScenario">
select * from api_scenario
<where>
id != #{request.id}
<if test="request.workspaceId != null">
AND project.workspace_id = #{request.workspaceId}
</if>

View File

@ -12,7 +12,7 @@ public interface ExtTestCaseReviewMapper {
List<TestCaseReviewDTO> list(@Param("request") QueryCaseReviewRequest params);
List<TestCaseReviewDTO> listByWorkspaceId(@Param("workspaceId") String workspaceId, @Param("userId") String userId);
List<TestCaseReviewDTO> listByWorkspaceId(@Param("workspaceId") String workspaceId, @Param("userId") String userId, @Param("projectId") String projectId);
List<TestReviewDTOWithMetric> listRelate(@Param("request") QueryTestReviewRequest request);

View File

@ -15,6 +15,9 @@
and test_case_review.name like CONCAT('%', #{request.name},'%')
</if>
and project.workspace_id = #{request.workspaceId}
<if test="request.projectId != null">
and test_case_review_project.project_id = #{request.projectId}
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
@ -32,6 +35,9 @@
test_case_review.id = test_case_review_project.review_id
and test_case_review_project.project_id = project.id
and project.workspace_id = #{workspaceId}
<if test="projectId != null">
and test_case_review_project.project_id = #{projectId}
</if>
and (
(test_case_review_users.review_id = test_case_review.id
and test_case_review_users.user_id = #{userId} )
@ -51,6 +57,9 @@
<if test="request.reviewerId != null">
and test_case_review_users.user_id = #{request.reviewerId}
</if>
<if test="request.projectId != null">
and test_case_review_project.project_id = #{request.projectId}
</if>
<if test="request.creator != null">
and (test_case_review.creator = #{request.creator}
<if test="request.reviewIds != null and request.reviewIds.size() > 0">

View File

@ -1,8 +1,8 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.track.dto.TestPlanDTO;
import io.metersphere.track.dto.TestPlanDTOWithMetric;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import io.metersphere.track.dto.TestPlanDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -13,4 +13,11 @@ public interface ExtTestPlanMapper {
List<TestPlanDTOWithMetric> listRelate(@Param("request") QueryTestPlanRequest params);
List<TestPlanDTO> planList(@Param("request") QueryTestPlanRequest params);
List<TestPlanDTO> selectByIds(@Param("list") List<String> ids);
int updatePlan(@Param("plan") TestPlanDTO plan);
List<TestPlanDTO> selectReference(@Param("request") QueryTestPlanRequest params);
}

View File

@ -114,6 +114,9 @@
<if test="request.workspaceId != null">
AND test_plan.workspace_id = #{request.workspaceId}
</if>
<if test="request.projectId != null">
AND test_plan_project.project_id = #{request.projectId}
</if>
<if test="request.id != null">
AND test_plan.id = #{request.id}
</if>
@ -160,16 +163,56 @@
</select>
<select id="listRelate" resultType="io.metersphere.track.dto.TestPlanDTOWithMetric">
select test_plan.* from test_plan
where test_plan.workspace_id = #{request.workspaceId}
and (test_plan.principal = #{request.principal}
<if test="request.planIds != null and request.planIds.size() > 0">
or test_plan.id in
<foreach collection="request.planIds" item="planId" open="(" close=")" separator=",">
#{planId}
</foreach>
</if>
)
select distinct test_plan.* from test_plan
inner join test_plan_project on test_plan.id = test_plan_project.test_plan_id
<where>
test_plan.workspace_id = #{request.workspaceId}
<if test="request.projectId != null">
and test_plan_project.project_id = #{request.projectId}
</if>
and (test_plan.principal = #{request.principal}
<if test="request.planIds != null and request.planIds.size() > 0">
or test_plan.id in
<foreach collection="request.planIds" item="planId" open="(" close=")" separator=",">
#{planId}
</foreach>
</if>
)
</where>
order by test_plan.update_time desc
</select>
<update id="updatePlan" parameterType="io.metersphere.track.dto.TestPlanDTO">
update test_plan
<set>
<if test="plan.apiIds != null">
api_ids = #{plan.apiIds,jdbcType=VARCHAR}
</if>
<if test="plan.scenarioIds != null">
scenario_ids = #{plan.scenarioIds,jdbcType=VARCHAR}
</if>
</set>
<where>
id = #{plan.id}
</where>
</update>
<select id="selectByIds" resultMap="BaseResultMap" parameterType="java.util.List">
SELECT * FROM TEST_PLAN p where p.id in
<foreach collection="list" item="planId" open="(" close=")" separator=",">
#{planId}
</foreach>
</select>
<select id="selectReference" resultMap="BaseResultMap" parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest">
SELECT * FROM TEST_PLAN p LEFT JOIN test_plan_project t ON t.test_plan_id=p.id
<where>
<if test="request.scenarioId != null">
AND p.scenario_ids like CONCAT('%', #{request.scenarioId},'%')
</if>
<if test="request.apiId != null">
AND p.api_ids like CONCAT('%', #{request.apiId},'%')
</if>
</where>
</select>
</mapper>

View File

@ -19,7 +19,7 @@ public interface ExtTestPlanTestCaseMapper {
List<TestPlanCaseDTO> listByNodes(@Param("request") QueryTestPlanCaseRequest request);
List<String> findRelateTestPlanId(@Param("userId") String userId, @Param("workspaceId") String workspaceId);
List<String> findRelateTestPlanId(@Param("userId") String userId, @Param("workspaceId") String workspaceId, @Param("projectId") String projectId);
List<TestPlanCaseDTO> getRecentTestedTestCase(@Param("request") QueryTestPlanCaseRequest request);

View File

@ -270,8 +270,15 @@
select distinct plan_id from test_plan_test_case
inner join test_plan
on test_plan_test_case.plan_id = test_plan.id
where test_plan_test_case.executor = #{userId}
and test_plan.workspace_id = #{workspaceId}
inner join test_plan_project
on test_plan.id = test_plan_project.test_plan_id
<where>
test_plan_test_case.executor = #{userId}
and test_plan.workspace_id = #{workspaceId}
<if test="projectId != null">
and test_plan_project.project_id = #{projectId}
</if>
</where>
</select>
<select id="getRecentTestedTestCase" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
select test_plan_test_case.*, test_case.*

View File

@ -11,7 +11,7 @@ public interface ExtTestReviewCaseMapper {
List<TestReviewCaseDTO> list(@Param("request") QueryCaseReviewRequest request);
List<String> getStatusByReviewId(String reviewId);
List<String> findRelateTestReviewId(@Param("userId") String userId, @Param("workspaceId") String workspaceId);
List<String> findRelateTestReviewId(@Param("userId") String userId, @Param("workspaceId") String workspaceId, @Param("projectId") String projectId);
/**
* 根据项目 ids 查询 TestReviewCaseDTO 列表

View File

@ -206,6 +206,7 @@
inner join project on project.id = test_case_review_project.project_id
where test_case_review_test_case.review_id = #{userId}
and project.workspace_id = #{workspaceId}
and test_case_review_project.project_id = #{projectId}
</select>
<select id="listTestCaseByProjectIds" resultType="io.metersphere.track.dto.TestReviewCaseDTO">
select distinct * from test_case_review_test_case, test_case

View File

@ -68,4 +68,8 @@ public class SessionUtils {
public static String getCurrentOrganizationId() {
return Optional.ofNullable(getUser()).orElse(new SessionUser()).getLastOrganizationId();
}
public static String getCurrentProjectId() {
return Optional.ofNullable(getUser()).orElse(new SessionUser()).getLastProjectId();
}
}

View File

@ -15,6 +15,8 @@ import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -49,7 +51,7 @@ public class PerformanceNoticeTask {
}
try {
//查询定时任务是否关闭
Thread.sleep(1000 * 30);// 每分钟检查 loadtest 的状态
Thread.sleep(1000 * 10);// 检查 loadtest 的状态
} catch (InterruptedException e) {
LogUtil.error(e.getMessage(), e);
}
@ -81,7 +83,11 @@ public class PerformanceNoticeTask {
if (PerformanceTestStatus.Error.name().equals(loadTestReport.getStatus())) {
event = NoticeConstants.Event.EXECUTE_FAILED;
}
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("testName", loadTestReport.getName());
paramMap.put("id", loadTestReport.getId());
paramMap.put("type", "performance");
paramMap.put("url", baseSystemConfigDTO.getUrl());
NoticeModel noticeModel = NoticeModel.builder()
.successContext(successContext)
.successMailTemplate("PerformanceApiSuccessNotification")
@ -91,6 +97,7 @@ public class PerformanceNoticeTask {
.status(loadTestReport.getStatus())
.subject(subject)
.event(event)
.paramMap(paramMap)
.build();
noticeSendService.send(loadTestReport.getTriggerMode(), noticeModel);
}

View File

@ -81,8 +81,7 @@ public class TestCaseReviewController {
@PostMapping("/list/all")
public List<TestCaseReview> listAll() {
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
return testCaseReviewService.listCaseReviewAll(currentWorkspaceId);
return testCaseReviewService.listCaseReviewAll();
}
@PostMapping("/relevance")

View File

@ -16,6 +16,10 @@ public class QueryTestPlanRequest extends TestPlan {
private List<String> planIds;
private String scenarioId;
private String apiId;
private List<OrderRequest> orders;
private Map<String, List<String>> filters;

View File

@ -35,4 +35,6 @@ public class QueryCaseReviewRequest extends TestCaseReviewTestCase {
private String method;
private Map<String, Object> combine;
private String projectId;
}

View File

@ -156,6 +156,7 @@ public class TestCaseReviewService {
public List<TestCaseReviewDTO> listCaseReview(QueryCaseReviewRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
request.setProjectId(SessionUtils.getCurrentProjectId());
return extTestCaseReviewMapper.list(request);
}
@ -198,7 +199,7 @@ public class TestCaseReviewService {
}
public List<TestCaseReviewDTO> recent(String currentWorkspaceId) {
return extTestCaseReviewMapper.listByWorkspaceId(currentWorkspaceId, SessionUtils.getUserId());
return extTestCaseReviewMapper.listByWorkspaceId(currentWorkspaceId, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId());
}
public void editCaseReview(SaveTestCaseReviewRequest testCaseReview) {
@ -346,21 +347,16 @@ public class TestCaseReviewService {
testCaseReviewTestCaseMapper.deleteByExample(testCaseReviewTestCaseExample);
}
public List<TestCaseReview> listCaseReviewAll(String currentWorkspaceId) {
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andWorkspaceIdEqualTo(currentWorkspaceId);
List<Project> projects = projectMapper.selectByExample(projectExample);
List<String> projectIds = projects.stream().map(Project::getId).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(projectIds)) {
TestCaseReviewProjectExample testCaseReviewProjectExample = new TestCaseReviewProjectExample();
testCaseReviewProjectExample.createCriteria().andProjectIdIn(projectIds);
List<TestCaseReviewProject> testCaseReviewProjects = testCaseReviewProjectMapper.selectByExample(testCaseReviewProjectExample);
List<String> reviewIds = testCaseReviewProjects.stream().map(TestCaseReviewProject::getReviewId).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(reviewIds)) {
public List<TestCaseReview> listCaseReviewAll() {
TestCaseReviewProjectExample reviewProjectExample = new TestCaseReviewProjectExample();
TestCaseReviewProjectExample.Criteria criteria = reviewProjectExample.createCriteria();
if (StringUtils.isNotBlank(SessionUtils.getCurrentProjectId())) {
criteria.andProjectIdEqualTo(SessionUtils.getCurrentProjectId());
List<TestCaseReviewProject> testCaseReviewProjects = testCaseReviewProjectMapper.selectByExample(reviewProjectExample);
if (!CollectionUtils.isEmpty(testCaseReviewProjects)) {
List<String> caseReviewIds = testCaseReviewProjects.stream().map(TestCaseReviewProject::getReviewId).collect(Collectors.toList());
TestCaseReviewExample testCaseReviewExample = new TestCaseReviewExample();
testCaseReviewExample.createCriteria().andIdIn(reviewIds);
testCaseReviewExample.createCriteria().andIdIn(caseReviewIds);
return testCaseReviewMapper.selectByExample(testCaseReviewExample);
}
}
@ -481,7 +477,8 @@ public class TestCaseReviewService {
request.setReviewerId(user.getId());
}
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
request.setReviewIds(extTestReviewCaseMapper.findRelateTestReviewId(user.getId(), SessionUtils.getCurrentWorkspaceId()));
request.setProjectId(SessionUtils.getCurrentProjectId());
request.setReviewIds(extTestReviewCaseMapper.findRelateTestReviewId(user.getId(), SessionUtils.getCurrentWorkspaceId(), user.getLastProjectId()));
List<String> projectIds = extProjectMapper.getProjectIdByWorkspaceId(SessionUtils.getCurrentWorkspaceId());
@ -545,9 +542,11 @@ public class TestCaseReviewService {
if (userIds.size() > 0) {
for (String id : userIds) {
stringBuilder.append(userMap.get(id)).append("");
if (StringUtils.isNotBlank(userMap.get(id))) {
stringBuilder.append(userMap.get(id)).append("");
}
}
name = stringBuilder.toString().substring(0, stringBuilder.length() - 1);
name = stringBuilder.substring(0, stringBuilder.length() - 1);
}
return name;
}

View File

@ -220,27 +220,17 @@ public class TestCaseService {
public List<TestCase> recentTestPlans(QueryTestCaseRequest request, int count) {
if (StringUtils.isBlank(request.getWorkspaceId())) {
return null;
}
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andWorkspaceIdEqualTo(request.getWorkspaceId());
List<String> projectIds = projectMapper.selectByExample(projectExample).stream()
.map(Project::getId).collect(Collectors.toList());
if (projectIds.isEmpty()) {
return null;
}
PageHelper.startPage(1, count, true);
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andProjectIdIn(projectIds).andMaintainerEqualTo(request.getUserId());
testCaseExample.setOrderByClause("update_time desc, sort desc");
return testCaseMapper.selectByExample(testCaseExample);
TestCaseExample.Criteria criteria = testCaseExample.createCriteria();
criteria.andMaintainerEqualTo(request.getUserId());
String projectId = SessionUtils.getCurrentProjectId();
if (StringUtils.isNotBlank(projectId)) {
criteria.andProjectIdEqualTo(projectId);
testCaseExample.setOrderByClause("update_time desc, sort desc");
return testCaseMapper.selectByExample(testCaseExample);
}
return new ArrayList<>();
}
public Project getProjectByTestCaseId(String testCaseId) {

View File

@ -327,6 +327,10 @@ public class TestPlanService {
public List<TestPlanDTOWithMetric> listTestPlan(QueryTestPlanRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
String projectId = SessionUtils.getCurrentProjectId();
if (StringUtils.isNotBlank(projectId)) {
request.setProjectId(projectId);
}
List<TestPlanDTOWithMetric> testPlans = extTestPlanMapper.list(request);
calcTestPlanRate(testPlans);
return testPlans;
@ -392,17 +396,41 @@ public class TestPlanService {
if (StringUtils.isBlank(currentWorkspaceId)) {
return null;
}
TestPlanExample testPlanTestCaseExample = new TestPlanExample();
testPlanTestCaseExample.createCriteria().andWorkspaceIdEqualTo(currentWorkspaceId)
.andPrincipalEqualTo(SessionUtils.getUserId());
testPlanTestCaseExample.setOrderByClause("update_time desc");
return testPlanMapper.selectByExample(testPlanTestCaseExample);
TestPlanProjectExample testPlanProjectExample = new TestPlanProjectExample();
TestPlanProjectExample.Criteria criteria = testPlanProjectExample.createCriteria();
if (StringUtils.isNotBlank(SessionUtils.getCurrentProjectId())) {
criteria.andProjectIdEqualTo(SessionUtils.getCurrentProjectId());
List<TestPlanProject> testPlanProjects = testPlanProjectMapper.selectByExample(testPlanProjectExample);
if (!CollectionUtils.isEmpty(testPlanProjects)) {
List<String> testPlanIds = testPlanProjects.stream().map(TestPlanProject::getTestPlanId).collect(Collectors.toList());
TestPlanExample testPlanTestCaseExample = new TestPlanExample();
testPlanTestCaseExample.createCriteria().andWorkspaceIdEqualTo(currentWorkspaceId)
.andIdIn(testPlanIds)
.andPrincipalEqualTo(SessionUtils.getUserId());
testPlanTestCaseExample.setOrderByClause("update_time desc");
return testPlanMapper.selectByExample(testPlanTestCaseExample);
}
}
return new ArrayList<>();
}
public List<TestPlan> listTestAllPlan(String currentWorkspaceId) {
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andWorkspaceIdEqualTo(currentWorkspaceId);
return testPlanMapper.selectByExample(testPlanExample);
TestPlanProjectExample testPlanProjectExample = new TestPlanProjectExample();
TestPlanProjectExample.Criteria criteria = testPlanProjectExample.createCriteria();
if (StringUtils.isNotBlank(SessionUtils.getCurrentProjectId())) {
criteria.andProjectIdEqualTo(SessionUtils.getCurrentProjectId());
List<TestPlanProject> testPlanProjects = testPlanProjectMapper.selectByExample(testPlanProjectExample);
if (!CollectionUtils.isEmpty(testPlanProjects)) {
List<String> testPlanIds = testPlanProjects.stream().map(TestPlanProject::getTestPlanId).collect(Collectors.toList());
TestPlanExample testPlanExample = new TestPlanExample();
TestPlanExample.Criteria testPlanCriteria = testPlanExample.createCriteria();
testPlanCriteria.andWorkspaceIdEqualTo(currentWorkspaceId);
testPlanCriteria.andIdIn(testPlanIds);
return testPlanMapper.selectByExample(testPlanExample);
}
}
return new ArrayList<>();
}
public List<TestPlanDTOWithMetric> listRelateAllPlan() {
@ -410,7 +438,8 @@ public class TestPlanService {
QueryTestPlanRequest request = new QueryTestPlanRequest();
request.setPrincipal(user.getId());
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
request.setPlanIds(extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId()));
request.setProjectId(SessionUtils.getCurrentProjectId());
request.setPlanIds(extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId(), SessionUtils.getCurrentProjectId()));
List<TestPlanDTOWithMetric> testPlans = extTestPlanMapper.listRelate(request);
calcTestPlanRate(testPlans);
return testPlans;

View File

@ -123,7 +123,7 @@ public class TestPlanTestCaseService {
public void buildQueryRequest(QueryTestPlanCaseRequest request, int count) {
SessionUser user = SessionUtils.getUser();
List<String> relateTestPlanIds = extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId());
List<String> relateTestPlanIds = extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId(), SessionUtils.getCurrentProjectId());
PageHelper.startPage(1, count, true);
request.setPlanIds(relateTestPlanIds);
request.setExecutor(user.getId());

View File

@ -0,0 +1 @@
alter table user add last_project_id varchar(50) null;

View File

@ -64,8 +64,8 @@
<!--要生成的数据库表 -->
<table tableName="api_scenario"/>
<table tableName="api_scenario_report"/>
<table tableName="api_scenario_report_detail"/>
</context>
</generatorConfiguration>

View File

@ -46,6 +46,14 @@ export default {
logoId: '_blank',
}
},
created() {
if (localStorage.getItem("store")) {
this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(localStorage.getItem("store"))))
}
window.addEventListener("beforeunload", () => {
localStorage.setItem("store", JSON.stringify(this.$store.state))
})
},
beforeCreate() {
this.$get("/isLogin").then(response => {
if (response.data.success) {

View File

@ -1,14 +1,13 @@
<template>
<ms-container>
<ms-aside-container>
<ms-api-scenario-module @selectModule="selectModule" @getApiModuleTree="initTree" @changeProject="changeProject"
<ms-api-scenario-module @selectModule="selectModule" @getApiModuleTree="initTree"
@refresh="refresh" @saveAsEdit="editScenario"/>
</ms-aside-container>
<ms-main-container>
<el-tabs v-model="activeName" @tab-click="addTab" @tab-remove="removeTab">
<el-tab-pane name="default" :label="$t('api_test.automation.scenario_test')">
<ms-api-scenario-list
:current-project="currentProject"
:current-module="currentModule"
@edit="editScenario"
ref="apiScenarioList"/>
@ -21,7 +20,7 @@
:name="item.name"
closable>
<div class="ms-api-scenario-div">
<ms-edit-api-scenario :current-project="currentProject" :currentScenario="item.currentScenario" :moduleOptions="moduleOptions"/>
<ms-edit-api-scenario :currentScenario="item.currentScenario" :moduleOptions="moduleOptions"/>
</div>
</el-tab-pane>
@ -53,7 +52,6 @@
return {
isHide: true,
activeName: 'default',
currentProject: null,
currentModule: null,
moduleOptions: {},
tabs: [],
@ -102,9 +100,6 @@
initTree(data) {
this.moduleOptions = data;
},
changeProject(data) {
this.currentProject = data;
},
refresh(data) {
this.$refs.apiScenarioList.search(data);
},

View File

@ -4,7 +4,7 @@
<el-card>
<section class="report-container" v-if="this.report.testId">
<ms-api-report-view-header :report="report" @reportExport="handleExport" @reportSave="handleSave"/>
<ms-api-report-view-header :debug="debug" :report="report" @reportExport="handleExport" @reportSave="handleSave"/>
<main v-if="this.isNotRunning">
<ms-metric-chart :content="content" :totalTime="totalTime"/>
@ -71,6 +71,7 @@
reportId: String,
currentProjectId: String,
infoDb: Boolean,
debug: Boolean,
},
watch: {
reportId() {
@ -178,6 +179,8 @@
this.$success(this.$t('commons.save_success'));
this.loading = false;
this.$emit('refresh');
}, error => {
this.loading = false;
});
},
exportReportReset() {

View File

@ -2,14 +2,14 @@
<header class="report-header">
<el-row>
<el-col>
<span><el-input size="mini" style="width: 200px" v-model="report.name"/> </span>
<span v-if="!debug"><el-input size="mini" style="width: 200px" v-model="report.name"/> </span>
<span class="time"> {{ report.createTime | timestampFormatDate }}</span>
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)" style="margin-right: 10px">
{{$t('test_track.plan_view.export_report')}}
</el-button>
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleSave(report.name)" style="margin-right: 10px">
<el-button v-if="!debug" :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleSave(report.name)" style="margin-right: 10px">
{{$t('commons.save')}}
</el-button>
@ -23,7 +23,10 @@
export default {
name: "MsApiReportViewHeader",
props: ['report'],
props: {
report: {},
debug: Boolean,
},
computed: {
path() {
return "/api/test/edit?id=" + this.report.testId;

View File

@ -1,34 +1,18 @@
<template>
<div class="metric-container">
<el-row type="flex">
<div class="metric">
<div class="value">{{request.responseResult.responseTime}} ms</div>
<div class="name">{{$t('api_report.response_time')}}</div>
<br>
<div class="value">{{request.responseResult.latency}} ms</div>
<div class="name">{{$t('api_report.latency')}}</div>
</div>
<div class="metric">
<div class="value">{{request.requestSize}} bytes</div>
<div class="name">{{$t('api_report.request_size')}}</div>
<br>
<div class="value">{{request.responseResult.responseSize}} bytes</div>
<div class="name">{{$t('api_report.response_size')}}</div>
</div>
<div class="metric horizontal">
<el-row type="flex">
<div class="code">
<div class="value" :class="{'error': error}">{{request.responseResult.responseCode}}</div>
<div class="name">{{$t('api_report.response_code')}}</div>
</div>
<div class="split"></div>
<div class="message">
<div class="value">{{request.responseResult.responseMessage}}</div>
<div class="name">{{$t('api_report.response_message')}}</div>
</div>
</el-row>
</div>
<el-col>
<div style="font-size: 14px;color: #AAAAAA;float: left">{{$t('api_report.response_code')}} :</div>
<div style="font-size: 14px;color:#61C550;margin-top:2px;margin-left:10px;float: left">{{request.responseResult.responseCode ? request.responseResult.responseCode :'0'}}</div>
</el-col>
<el-col>
<div style="font-size: 14px;color: #AAAAAA;float: left">{{$t('api_report.response_time')}} :</div>
<div style="font-size: 14px;color:#61C550;margin-top:2px;margin-left:10px;float: left">{{request.responseResult.responseTime?request.responseResult.responseTime:0}} ms</div>
</el-col>
<el-col>
<div style="font-size: 14px;color: #AAAAAA;float: left">{{$t('api_report.response_size')}} :</div>
<div style="font-size: 14px;color:#61C550; margin-top:2px;margin-left:10px;float: left">{{request.responseResult.responseSize?request.responseResult.responseSize:0}} bytes</div>
</el-col>
</el-row>
</div>
</template>

View File

@ -3,7 +3,7 @@
<p class="el-divider--horizontal"></p>
<div @click="active">
<el-row :gutter="10" type="flex" align="middle" class="info">
<el-col :span="10" v-if="indexNumber!=undefined">
<el-col :span="14" v-if="indexNumber!=undefined">
<div class="method">
<div class="el-step__icon is-text ms-api-col" v-if="indexNumber%2 ==0">
<div class="el-step__icon-inner"> {{ indexNumber+1 }}</div>
@ -14,14 +14,10 @@
{{ request.name }}
</div>
</el-col>
<el-col :span="4">
<div class="method">
{{ request.method }}
</div>
</el-col>
<el-col :span="5">
<el-tooltip effect="dark" :content="request.responseResult.responseCode" placement="bottom" :open-delay="800">
<div class="url">{{ request.responseResult.responseCode }}</div>
<div class="url" style="color: #5daf34">{{ request.responseResult.responseCode }}</div>
</el-tooltip>
</el-col>
<el-col :span="3">
@ -122,16 +118,18 @@
}
.ms-api-col {
background-color: #FCF1F1;
border-color: #67C23A;
background-color: #EFF0F0;
border-color: #EFF0F0;
margin-right: 10px;
color: #67C23A;
font-size: 12px;
color: #64666A;
}
.ms-api-col-create {
background-color: #EBF2F2;
border-color: #008080;
margin-right: 10px;
font-size: 12px;
color: #008080;
}

View File

@ -1,27 +1,6 @@
<template>
<div class="request-result">
<div @click="active">
<el-row :gutter="10" type="flex" align="middle" class="info">
<el-col :span="12">
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
{{scenarioName}}
</el-col>
<el-col :span="4">
{{$t('api_report.start_time')}}
</el-col>
<el-col :span="2">
{{$t('api_report.response_time')}}
</el-col>
<el-col :span="2">
{{$t('api_report.error')}}
</el-col>
<el-col :span="2">
{{$t('api_report.assertions')}}
</el-col>
<el-col :span="2">
{{$t('api_report.result')}}
</el-col>
</el-row>
<div>
<el-row :gutter="10" type="flex" align="middle" class="info">
<el-col :span="2">
<div class="method">
@ -35,7 +14,7 @@
</el-tooltip>
</el-col>
<el-col :span="4">
{{request.startTime | timestampFormatDate(true) }}
{{request.startTime | timestampFormatDate(true) }}
</el-col>
<el-col :span="2">
<div class="time">
@ -67,7 +46,7 @@
</el-tab-pane>
<el-tab-pane :label="$t('api_report.request_result')" name="result">
<ms-request-metric :request="request"/>
<ms-request-text :request="request"/>
<ms-request-text :request="request"/>
<br>
<ms-response-text :request-type="requestType" :response="request.responseResult"/>
</el-tab-pane>

View File

@ -58,9 +58,8 @@
<script>
import {WORKSPACE_ID} from '@/common/js/constants';
import {getCurrentUser, getUUID} from "@/common/js/utils";
import {getCurrentUser, getUUID,getCurrentProjectID} from "@/common/js/utils";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
export default {
name: "MsAddBasisScenario",
components: {MsDialogFooter},
@ -70,7 +69,6 @@ export default {
scenarioForm: {},
visible: false,
currentModule: {},
projectId: "",
userOptions: [],
rule: {
name: [
@ -107,7 +105,7 @@ export default {
})
},
setParameter() {
this.scenarioForm.projectId = this.projectId;
this.scenarioForm.projectId = getCurrentProjectID();
this.scenarioForm.id = getUUID().substring(0, 8);
this.scenarioForm.protocol = this.currentProtocol;
if (this.currentModule != null) {
@ -121,10 +119,9 @@ export default {
this.userOptions = response.data;
});
},
open(currentModule, projectId) {
open(currentModule) {
this.scenarioForm = {principal: getCurrentUser().id};
this.currentModule = currentModule;
this.projectId = projectId;
this.getMaintainerOptions();
this.visible = true;
}

View File

@ -38,10 +38,9 @@
<script>
import {WORKSPACE_ID} from '@/common/js/constants';
import {getCurrentUser, getUUID} from "@/common/js/utils";
import {getCurrentUser, getUUID,getCurrentProjectID} from "@/common/js/utils";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import MsTablePagination from "../../../common/pagination/TablePagination";
export default {
name: "MsAddTag",
components: {MsDialogFooter,MsTablePagination},
@ -94,8 +93,8 @@
setParameter() {
this.tagForm.projectId = this.projectId;
},
open(projectId) {
this.projectId = projectId;
open() {
this.projectId = getCurrentProjectID();
this.visible = true;
this.initTable();
},

View File

@ -12,7 +12,7 @@
<i class="icon el-icon-arrow-right" :class="{'is-active': request.active}"
@click="active(request)" v-if="request.referenced!=undefined && request.referenced!='Deleted' && request.referenced!='REF'"/>
<span>{{request.type!= 'create' ? request.name:''}} </span>
<el-tag size="mini" style="margin-left: 20px" v-if="request.referenced==='Deleted'" type="danger">引用不存在</el-tag>
<el-tag size="mini" style="margin-left: 20px" v-if="request.referenced==='Deleted'" type="danger">{{$t('api_test.automation.reference_deleted')}}</el-tag>
<el-tag size="mini" style="margin-left: 20px" v-if="request.referenced ==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag>
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="remove" style="margin-right: 20px; float: right"/>
@ -21,11 +21,18 @@
<!-- 请求参数-->
<el-collapse-transition>
<div v-if="request.active">
<div v-if="request.protocol === 'HTTP'">
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-model="request.url" style="width: 85%;margin-top: 10px" size="small">
<el-select v-model="request.method" slot="prepend" style="width: 100px" size="small">
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-input>
</div>
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :headers="request.headers " :request="request" v-if="request.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="request" :currentProject="currentProject" v-if="request.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="request" :currentProject="currentProject" v-if="request.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="request" :currentProject="currentProject" v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'"/>
<ms-tcp-basis-parameters :request="request" v-if="request.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="request" v-if="request.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="request" v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'"/>
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)" v-if="!request.referenced">
{{$t('commons.save')}}
@ -41,17 +48,43 @@
import MsTcpBasisParameters from "../../definition/components/request/tcp/BasisParameters";
import MsDubboBasisParameters from "../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../definition/components/request/http/ApiRequestForm";
import {REQ_METHOD} from "../../definition/model/JsonData";
export default {
name: "MsApiComponent",
props: {
request: {},
node: {},
currentProject: {},
},
components: {MsSqlBasisParameters, MsTcpBasisParameters, MsDubboBasisParameters, MsApiRequestForm},
data() {
return {loading: false,}
return {loading: false, reqOptions: REQ_METHOD,}
},
created() {
if (this.request.id && this.request.referenced === 'REF') {
this.$get("/api/definition/get/" + this.request.id, response => {
if (response.data) {
this.request.name = response.data.name;
this.reload();
} else {
this.request.referenced = "Deleted";
}
})
}
if (this.request.protocol === 'HTTP') {
try {
let urlObject = new URL(this.request.url);
let url = urlObject.protocol + "//" + urlObject.host + "/";
let path = this.request.url.substr(url.length);
if (!path.startsWith('/')) {
path = "/" + path;
}
this.request.path = path;
} catch (e) {
this.request.path = this.request.url;
}
}
},
methods: {
remove() {
@ -94,4 +127,12 @@
transform: rotate(90deg);
}
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 20px 0;
}
</style>

View File

@ -14,10 +14,9 @@
</el-form>
<!--不同协议请求-->
<ms-debug-http-page :scenario="true" :current-api="request" @saveAs="editApi" :currentProtocol="request.protocol" v-if="request.protocol==='HTTP'"/>
<ms-debug-jdbc-page :scenario="true" :currentProtocol="request.protocol" @saveAs="editApi" :currentProject="currentProject" v-if="request.protocol==='SQL'"/>
<ms-debug-tcp-page :scenario="true" :currentProtocol="request.protocol" @saveAs="editApi" :currentProject="currentProject" v-if="request.protocol==='TCP'"/>
<ms-debug-dubbo-page :scenario="true" :currentProtocol="request.protocol" @saveAs="editApi" :currentProject="currentProject" v-if="request.protocol==='DUBBO'"/>
<ms-debug-jdbc-page :scenario="true" :currentProtocol="request.protocol" @saveAs="editApi" v-if="request.protocol==='SQL'"/>
<ms-debug-tcp-page :scenario="true" :currentProtocol="request.protocol" @saveAs="editApi" v-if="request.protocol==='TCP'"/>
<ms-debug-dubbo-page :scenario="true" :currentProtocol="request.protocol" @saveAs="editApi" v-if="request.protocol==='DUBBO'"/>
</el-card>
</div>
</template>
@ -33,7 +32,6 @@
name: "ApiCustomize",
props: {
node: {},
currentProject: {},
request: {},
},
components: {MsDebugHttpPage, MsDebugJdbcPage, MsDebugTcpPage, MsDebugDubboPage},
@ -58,6 +56,10 @@
let name = this.request.name;
Object.assign(this.request, row.request);
this.request.name = name;
if (this.request.protocol === 'HTTP') {
this.request.url = row.url;
this.request.method = row.method;
}
this.request.resourceId = getUUID();
this.$emit('addCustomizeApi', this.request);
},
@ -72,5 +74,12 @@
</script>
<style scoped>
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 20px 0;
}
</style>

View File

@ -6,7 +6,7 @@
<div class="el-step__icon-inner">{{scenario.index}}</div>
</div>
<div style="margin-left: 20px;float: left"> {{scenario.name}}</div>
<el-tag size="mini" style="margin-left: 20px" v-if="scenario.referenced==='Deleted'" type="danger">引用不存在</el-tag>
<el-tag size="mini" style="margin-left: 20px" v-if="scenario.referenced==='Deleted'" type="danger">{{$t('api_test.automation.reference_deleted')}}</el-tag>
<el-tag size="mini" style="margin-left: 20px" v-if="scenario.referenced==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag>
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="remove" style="margin-right: 20px; float: right"/>
</el-row>
@ -25,7 +25,6 @@
props: {
scenario: {},
node: {},
currentProject: {},
},
watch: {},
created() {
@ -70,13 +69,6 @@
color: #606266;
}
.ms-api-col-create {
background-color: #EBF2F2;
border-color: #008080;
margin-right: 10px;
color: #008080;
}
/deep/ .el-card__body {
padding: 15px;
}

View File

@ -1,6 +1,6 @@
<template>
<div>
<el-card class="table-card" v-loading="result.loading">
<el-card class="table-card" v-loading="loading">
<template v-slot:header>
<ms-table-header :condition.sync="condition" @search="search" title=""
:show-create="false"/>
@ -37,32 +37,40 @@
</template>
</el-table-column>
<el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/>
<el-table-column prop="status" :label="$t('api_test.automation.last_result')">
<el-table-column prop="lastResult" :label="$t('api_test.automation.last_result')">
<template v-slot:default="{row}">
<el-link type="success" v-if="row.status === 'Success'">{{ $t('api_test.automation.success') }}</el-link>
<el-link type="danger" v-if="row.status === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link>
<el-link type="warning" v-if="row.status === 'Trash'">{{ $t('api_test.automation.trash') }}</el-link>
<el-link type="success" @click="showReport(row)" v-if="row.lastResult === 'Success'">{{ $t('api_test.automation.success') }}</el-link>
<el-link type="danger" @click="showReport(row)" v-if="row.lastResult === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link>
</template>
</el-table-column>
<el-table-column prop="passingRate" :label="$t('api_test.automation.passing_rate')"
<el-table-column prop="passRate" :label="$t('api_test.automation.passing_rate')"
show-overflow-tooltip/>
<el-table-column :label="$t('commons.operating')" width="240">
<el-table-column :label="$t('commons.operating')" width="200px" v-if="!referenced">
<template v-slot:default="{row}">
<el-button type="text" @click="edit(row)">{{ $t('api_test.automation.edit') }}</el-button>
<el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button>
<el-button type="text" @click="copy(row)">{{ $t('api_test.automation.copy') }}</el-button>
<el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button>
<ms-scenario-extend-buttons :row="row"/>
<div v-if="currentModule!=undefined && currentModule.id === 'gc'">
<el-button type="text" @click="reductionApi(row)">恢复</el-button>
<el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button>
</div>
<div v-else>
<el-button type="text" @click="edit(row)">{{ $t('api_test.automation.edit') }}</el-button>
<el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button>
<el-button type="text" @click="copy(row)">{{ $t('api_test.automation.copy') }}</el-button>
<el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button>
<ms-scenario-extend-buttons :row="row"/>
</div>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
<div>
<!-- 调试结果 -->
<!-- 执行结果 -->
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProject!=undefined ? currentProject.id:''"/>
<ms-api-report-detail @refresh="search" :infoDb="infoDb" :report-id="reportId" :currentProjectId="projectId"/>
</el-drawer>
<!--测试计划-->
<el-drawer :visible.sync="planVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-test-plan-list @addTestPlan="addTestPlan"/>
</el-drawer>
</div>
</el-card>
@ -75,21 +83,28 @@
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import MsTag from "../../../common/components/MsTag";
import {getUUID} from "@/common/js/utils";
import {getUUID, getCurrentProjectID} from "@/common/js/utils";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsTableMoreBtn from "./TableMoreBtn";
import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns";
import MsTestPlanList from "./testplan/TestPlanList";
export default {
name: "MsApiScenarioList",
components: {MsScenarioExtendButtons, ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag, MsApiReportDetail},
components: {MsTablePagination, MsTableMoreBtn, ShowMoreBtn, MsTableHeader, MsTag, MsApiReportDetail, MsScenarioExtendButtons, MsTestPlanList},
props: {
currentProject: Object,
currentModule: Object,
referenced: {
type: Boolean,
default: false,
}
},
data() {
return {
result: {},
loading: false,
condition: {},
currentScenario: {},
schedule: {},
selectAll: false,
selection: [],
tableData: [],
@ -97,7 +112,10 @@
pageSize: 10,
total: 0,
reportId: "",
infoDb: false,
runVisible: false,
planVisible: false,
projectId: "",
runData: [],
buttons: [
{
@ -108,16 +126,18 @@
],
}
},
created() {
this.projectId = getCurrentProjectID();
this.search();
},
watch: {
currentProject() {
this.search();
},
currentModule() {
this.search();
},
},
methods: {
search() {
this.loading = true;
this.condition.filters = ["Prepare", "Underway", "Completed"];
if (this.currentModule != null) {
if (this.currentModule.id === "root") {
@ -129,15 +149,16 @@
this.condition.moduleIds = this.currentModule.ids;
}
}
if (this.currentProject != null) {
this.condition.projectId = this.currentProject.id;
if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
let url = "/api/automation/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => {
this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.loading = false;
});
},
handleCommand(cmd) {
@ -153,15 +174,23 @@
}
},
handleBatchAddCase() {
this.planVisible = true;
},
addTestPlan(plans) {
let obj = {planIds: plans, scenarioIds: this.selection};
this.planVisible = false;
this.$post("/api/automation/scenario/plan", obj, response => {
this.$success(this.$t("commons.save_success"));
});
},
handleBatchExecute() {
this.infoDb = false;
let url = "/api/automation/run";
let run = {};
let scenarioIds = this.selection;
run.id = getUUID();
run.scenarioIds = scenarioIds;
this.result = this.$post(url, run, response => {
this.$post(url, run, response => {
let data = response.data;
this.runVisible = true;
this.reportId = run.id;
@ -180,14 +209,22 @@
edit(row) {
this.$emit('edit', row);
},
reductionApi(row) {
let obj = {id: row.id, projectId: row.projectId, name: row.name, status: 'Underway'}
this.$fileUpload("/api/automation/update", null, [], obj, () => {
this.$success(this.$t('commons.save_success'));
this.search();
})
},
execute(row) {
this.infoDb = false;
let url = "/api/automation/run";
let run = {};
let scenarioIds = [];
scenarioIds.push(row.id);
run.id = getUUID();
run.scenarioIds = scenarioIds;
this.result = this.$post(url, run, response => {
this.$post(url, run, response => {
let data = response.data;
this.runVisible = true;
this.reportId = run.id;
@ -197,6 +234,11 @@
row.id = getUUID();
this.$emit('edit', row);
},
showReport(row) {
this.runVisible = true;
this.infoDb = true;
this.reportId = row.reportId;
},
remove(row) {
if (this.currentModule !== undefined && this.currentModule != null && this.currentModule.id === "gc") {
this.$get('/api/automation/delete/' + row.id, () => {

View File

@ -1,10 +1,5 @@
<template>
<div>
<select-menu
:data="projects"
:current-data="currentProject"
:title="$t('test_track.project')"
@dataChange="changeProject" style="margin-bottom: 20px"/>
<el-input style="width: 275px;" :placeholder="$t('test_track.module.search')" v-model="filterText"
size="small">
<template v-slot:append>
@ -81,381 +76,365 @@
</template>
<script>
import SelectMenu from "../../../track/common/SelectMenu";
import MsAddBasisScenario from "@/business/components/api/automation/scenario/AddBasisScenario";
import SelectMenu from "../../../track/common/SelectMenu";
import MsAddBasisScenario from "@/business/components/api/automation/scenario/AddBasisScenario";
import {getCurrentProjectID} from "@/common/js/utils";
export default {
name: 'MsApiScenarioModule',
components: {
MsAddBasisScenario,
SelectMenu,
},
data() {
return {
httpVisible: false,
expandedNode: [],
filterText: "",
nextFlag: true,
currentProject: {},
projects: [],
currentModule: {},
newLabel: "",
data: [{
"id": "gc",
"name": "回收站",
"level": 1,
"children": [],
}, {
"id": "root",
"name": "默认模块",
"level": 0,
"children": [],
}]
}
},
mounted() {
this.getProjects();
this.changeProtocol();
},
watch: {
currentProject() {
this.getApiModuleTree();
this.$emit('changeProject', this.currentProject);
export default {
name: 'MsApiScenarioModule',
components: {
MsAddBasisScenario,
SelectMenu,
},
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
getApiModuleTree() {
if (this.currentProject) {
if (this.expandedNode.length === 0) {
this.expandedNode.push("root");
}
this.$get("/api/automation/module/list/" + this.currentProject.id, response => {
if (response.data !== undefined && response.data !== null) {
this.data[1].children = response.data;
let moduleOptions = [];
this.data[1].children.forEach(node => {
this.buildNodePath(node, {path: ''}, moduleOptions);
});
this.$emit('getApiModuleTree', moduleOptions);
data() {
return {
httpVisible: false,
expandedNode: [],
filterText: "",
nextFlag: true,
currentModule: {},
newLabel: "",
data: [{
"id": "gc",
"name": "回收站",
"level": 1,
"children": [],
}, {
"id": "root",
"name": "默认模块",
"level": 0,
"children": [],
}]
}
},
mounted() {
this.changeProtocol();
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
getApiModuleTree() {
let projectId = getCurrentProjectID();
if (projectId) {
if (this.expandedNode.length === 0) {
this.expandedNode.push("root");
}
});
}
},
buildNodePath(node, option, moduleOptions) {
//
option.id = node.id;
option.path = option.path + '/' + node.name;
node.path = option.path;
moduleOptions.push(option);
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
this.buildNodePath(node.children[i], {path: option.path}, moduleOptions);
this.$get("/api/automation/module/list/" + projectId, response => {
if (response.data !== undefined && response.data !== null) {
this.data[1].children = response.data;
let moduleOptions = [];
this.data[1].children.forEach(node => {
this.buildNodePath(node, {path: ''}, moduleOptions);
});
this.$emit('getApiModuleTree', moduleOptions);
}
});
}
}
},
findTreeByNodeId(rootNode, nodeId) {
if (rootNode.id === nodeId) {
return rootNode;
}
if (rootNode.children) {
for (let i = 0; i < rootNode.children.length; i++) {
if (this.findTreeByNodeId(rootNode.children[i], nodeId)) {
return rootNode;
},
buildNodePath(node, option, moduleOptions) {
//
option.id = node.id;
option.path = option.path + '/' + node.name;
node.path = option.path;
moduleOptions.push(option);
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
this.buildNodePath(node.children[i], {path: option.path}, moduleOptions);
}
}
}
},
buildParam(draggingNode, dropNode, dropType) {
let param = {};
param.id = draggingNode.data.id;
param.name = draggingNode.data.name;
param.projectId = draggingNode.data.projectId;
if (dropType === "inner") {
param.parentId = dropNode.data.id;
param.level = dropNode.data.level;
} else {
if (!dropNode.parent.id || dropNode.parent.id === 0) {
param.parentId = 0;
param.level = 1;
},
findTreeByNodeId(rootNode, nodeId) {
if (rootNode.id === nodeId) {
return rootNode;
}
if (rootNode.children) {
for (let i = 0; i < rootNode.children.length; i++) {
if (this.findTreeByNodeId(rootNode.children[i], nodeId)) {
return rootNode;
}
}
}
},
buildParam(draggingNode, dropNode, dropType) {
let param = {};
param.id = draggingNode.data.id;
param.name = draggingNode.data.name;
param.projectId = draggingNode.data.projectId;
if (dropType === "inner") {
param.parentId = dropNode.data.id;
param.level = dropNode.data.level;
} else {
param.parentId = dropNode.parent.data.id;
param.level = dropNode.parent.data.level;
}
}
let nodeIds = [];
this.getChildNodeId(draggingNode.data, nodeIds);
if (dropNode.level === 1 && dropType !== "inner") {
param.nodeTree = draggingNode.data;
} else {
for (let i = 0; i < this.data.length; i++) {
param.nodeTree = this.findTreeByNodeId(this.data[i], dropNode.data.id);
if (param.nodeTree) {
break;
if (!dropNode.parent.id || dropNode.parent.id === 0) {
param.parentId = 0;
param.level = 1;
} else {
param.parentId = dropNode.parent.data.id;
param.level = dropNode.parent.data.level;
}
}
}
param.nodeIds = nodeIds;
return param;
},
getTreeNode(nodes, id, list) {
if (!nodes) {
return;
}
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].id === id) {
i - 1 >= 0 ? list[0] = nodes[i - 1].id : list[0] = "";
list[1] = nodes[i].id;
i + 1 < nodes.length ? list[2] = nodes[i + 1].id : list[2] = "";
return;
}
if (nodes[i].children) {
this.getTreeNode(nodes[i].children, id, list);
}
}
},
handleDragEnd(draggingNode, dropNode, dropType) {
if (dropNode.data.id === "root" || dropType === "none" || dropType === undefined) {
return;
}
let param = this.buildParam(draggingNode, dropNode, dropType);
this.list = [];
if (param.parentId === "root") {
param.parentId = null;
}
this.getTreeNode(this.data, draggingNode.data.id, this.list);
this.$post("/api/automation/module/drag", param, () => {
this.getApiModuleTree();
}, () => {
this.getApiModuleTree();
});
},
allowDrop(draggingNode, dropNode) {
return dropNode.data.id !== "root";
},
allowDrag(draggingNode) {
//
return draggingNode.data.id !== "root";
},
append(node, data) {
if (this.nextFlag === true) {
const newChild = {
id: "newId",
isEdit: 0,
name: "",
children: []
}
if (!data.children) {
this.$set(data, 'children', [])
}
this.nextFlag = false;
data.children.push(newChild)
this.edit(node, newChild);
} else {
this.$message.warning(this.$t('commons.please_save'));
}
},
remove(node, data) {
if (data.name === "") {
this.nextFlag = true;
}
let delIds = [];
this.getChildNodeId(data, delIds);
delIds.push(data.id);
this.$post("/api/automation/module/delete", delIds, () => {
this.$success(this.$t('commons.save_success'));
//
const parent = node.parent
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.id !== undefined && data.id !== undefined && d.id === data.id)
children.splice(index, 1);
});
},
edit(node, data) {
this.$set(data, 'isEdit', 1)
this.newLabel = data.name
this.$nextTick(() => {
})
},
submitEdit(node, data) {
//
if (this.newLabel === "") {
this.nextFlag = false;
this.$message.warning(this.$t('commons.input_name'));
return;
}
this.$set(data, 'name', this.newLabel)
let flag = this.editApiModule(node, data);
if (flag === false) {
this.$set(data, 'isEdit', 1)
return;
}
this.$set(data, 'isEdit', 0)
this.newLabel = ""
this.nextFlag = true;
},
cancelEdit(node, data) {
this.newLabel = ""
this.$set(data, 'isEdit', 0)
},
getChildNodeId(rootNode, nodeIds) {
//ID
nodeIds.push(rootNode.id);
this.nodePath += rootNode.name + "/";
if (rootNode.children) {
for (let i = 0; i < rootNode.children.length; i++) {
this.getChildNodeId(rootNode.children[i], nodeIds);
}
}
},
//
editApiModule(node, data) {
if (!this.currentProject) {
this.$error("$t('api_test.select_project')");
return;
}
let url = "";
if (data.id === "newId") {
url = '/api/automation/module/add';
data.level = 1;
if (node.parent && node.parent.key !== "root") {
data.parentId = node.parent.key;
data.level = node.parent.level;
}
} else {
url = '/api/automation/module/edit';
let ids = [];
this.getChildNodeId(data, ids);
data.nodeIds = ids;
}
data.protocol = this.protocol;
data.projectId = this.currentProject.id;
this.$post(url, data, () => {
this.$success(this.$t('commons.save_success'));
this.getApiModuleTree();
this.nextFlag = true;
return true;
});
return false;
},
selectModule(data) {
if (data.id !== "root") {
if (data.path !== undefined && !data.path.startsWith("/")) {
data.path = "/" + data.path;
}
if (data.path !== undefined && data.path.endsWith("/")) {
data.path = data.path.substr(0, data.path.length - 1);
}
let nodeIds = [];
this.getChildNodeId(data, nodeIds);
data.ids = nodeIds;
this.currentModule = data;
}
this.$emit('selectModule', data);
},
refresh(data) {
this.$emit('refresh', data);
},
saveAsEdit(data) {
this.$emit('saveAsEdit', data);
},
filterNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
addScenario() {
this.$refs.basisScenario.open(this.currentModule, this.currentProject.id);
},
//
changeProject(project) {
this.currentProject = project;
},
getProjects() {
this.$get("/project/listAll", (response) => {
this.projects = response.data;
if (this.projects.length > 0) {
this.currentProject = this.projects[0];
this.getChildNodeId(draggingNode.data, nodeIds);
if (dropNode.level === 1 && dropType !== "inner") {
param.nodeTree = draggingNode.data;
} else {
for (let i = 0; i < this.data.length; i++) {
param.nodeTree = this.findTreeByNodeId(this.data[i], dropNode.data.id);
if (param.nodeTree) {
break;
}
}
}
});
},
nodeExpand(data) {
if (data.id) {
this.expandedNode.push(data.id);
param.nodeIds = nodeIds;
return param;
},
getTreeNode(nodes, id, list) {
if (!nodes) {
return;
}
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].id === id) {
i - 1 >= 0 ? list[0] = nodes[i - 1].id : list[0] = "";
list[1] = nodes[i].id;
i + 1 < nodes.length ? list[2] = nodes[i + 1].id : list[2] = "";
return;
}
if (nodes[i].children) {
this.getTreeNode(nodes[i].children, id, list);
}
}
},
handleDragEnd(draggingNode, dropNode, dropType) {
if (dropNode.data.id === "root" || dropType === "none" || dropType === undefined) {
return;
}
let param = this.buildParam(draggingNode, dropNode, dropType);
this.list = [];
if (param.parentId === "root") {
param.parentId = null;
}
this.getTreeNode(this.data, draggingNode.data.id, this.list);
this.$post("/api/automation/module/drag", param, () => {
this.getApiModuleTree();
}, () => {
this.getApiModuleTree();
});
},
allowDrop(draggingNode, dropNode) {
return dropNode.data.id !== "root";
},
allowDrag(draggingNode) {
//
return draggingNode.data.id !== "root";
},
append(node, data) {
if (this.nextFlag === true) {
const newChild = {
id: "newId",
isEdit: 0,
name: "",
children: []
}
if (!data.children) {
this.$set(data, 'children', [])
}
this.nextFlag = false;
data.children.push(newChild)
this.edit(node, newChild);
} else {
this.$message.warning(this.$t('commons.please_save'));
}
},
remove(node, data) {
if (data.name === "") {
this.nextFlag = true;
}
let delIds = [];
this.getChildNodeId(data, delIds);
delIds.push(data.id);
this.$post("/api/automation/module/delete", delIds, () => {
this.$success(this.$t('commons.save_success'));
//
const parent = node.parent
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.id !== undefined && data.id !== undefined && d.id === data.id)
children.splice(index, 1);
});
},
edit(node, data) {
this.$set(data, 'isEdit', 1)
this.newLabel = data.name
this.$nextTick(() => {
})
},
submitEdit(node, data) {
//
if (this.newLabel === "") {
this.nextFlag = false;
this.$message.warning(this.$t('commons.input_name'));
return;
}
this.$set(data, 'name', this.newLabel)
let flag = this.editApiModule(node, data);
if (flag === false) {
this.$set(data, 'isEdit', 1)
return;
}
this.$set(data, 'isEdit', 0)
this.newLabel = ""
this.nextFlag = true;
},
cancelEdit(node, data) {
this.newLabel = ""
this.$set(data, 'isEdit', 0)
},
getChildNodeId(rootNode, nodeIds) {
//ID
nodeIds.push(rootNode.id);
this.nodePath += rootNode.name + "/";
if (rootNode.children) {
for (let i = 0; i < rootNode.children.length; i++) {
this.getChildNodeId(rootNode.children[i], nodeIds);
}
}
},
//
editApiModule(node, data) {
let projectId = getCurrentProjectID();
if (!projectId) {
this.$error("$t('api_test.select_project')");
return;
}
let url = "";
if (data.id === "newId") {
url = '/api/automation/module/add';
data.level = 1;
if (node.parent && node.parent.key !== "root") {
data.parentId = node.parent.key;
data.level = node.parent.level;
}
} else {
url = '/api/automation/module/edit';
let ids = [];
this.getChildNodeId(data, ids);
data.nodeIds = ids;
}
data.protocol = this.protocol;
data.projectId = projectId;
this.$post(url, data, () => {
this.$success(this.$t('commons.save_success'));
this.getApiModuleTree();
this.nextFlag = true;
return true;
});
return false;
},
selectModule(data) {
if (data.id !== "root") {
if (data.path !== undefined && !data.path.startsWith("/")) {
data.path = "/" + data.path;
}
if (data.path !== undefined && data.path.endsWith("/")) {
data.path = data.path.substr(0, data.path.length - 1);
}
let nodeIds = [];
this.getChildNodeId(data, nodeIds);
data.ids = nodeIds;
this.currentModule = data;
}
this.$emit('selectModule', data);
},
refresh(data) {
this.$emit('refresh', data);
},
saveAsEdit(data) {
this.$emit('saveAsEdit', data);
},
filterNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
addScenario() {
this.$refs.basisScenario.open(this.currentModule);
},
nodeExpand(data) {
if (data.id) {
this.expandedNode.push(data.id);
}
},
nodeCollapse(data) {
if (data.id) {
this.expandedNode.splice(this.expandedNode.indexOf(data.id), 1);
}
},
changeProtocol() {
this.getApiModuleTree();
this.$emit('changeProtocol', this.protocol);
}
},
nodeCollapse(data) {
if (data.id) {
this.expandedNode.splice(this.expandedNode.indexOf(data.id), 1);
}
},
changeProtocol() {
this.getApiModuleTree();
this.$emit('changeProtocol', this.protocol);
}
}
}
</script>
<style scoped>
.node-tree {
margin-top: 15px;
margin-bottom: 15px;
}
.node-tree {
margin-top: 15px;
margin-bottom: 15px;
}
.ms-el-input {
height: 25px;
line-height: 25px;
}
.ms-el-input {
height: 25px;
line-height: 25px;
}
.custom-tree-node {
flex: 1 1 auto;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
width: 100%;
}
.custom-tree-node {
flex: 1 1 auto;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
width: 100%;
}
.father .child {
display: none;
}
.father .child {
display: none;
}
.father:hover .child {
display: block;
}
.father:hover .child {
display: block;
}
.node-title {
width: 0;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 auto;
padding: 0 5px;
overflow: hidden;
}
.node-title {
width: 0;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 auto;
padding: 0 5px;
overflow: hidden;
}
.node-operate > i {
color: #409eff;
margin: 0 5px;
}
.node-operate > i {
color: #409eff;
margin: 0 5px;
}
/deep/ .el-tree-node__content {
height: 33px;
}
/deep/ .el-tree-node__content {
height: 33px;
}
.ms-api-buttion {
width: 30px;
}
.ms-api-buttion {
width: 30px;
}
</style>

View File

@ -93,7 +93,6 @@
testPlan.hashTree.push(threadGroup);
let reqObj = {id: this.reportId, reportId: this.reportId, environmentId: this.environment, testElement: testPlan};
let bodyFiles = this.getBodyUploadFiles(reqObj);
console.log(bodyFiles)
let url = "/api/automation/run/debug";
this.$fileUpload(url, null, bodyFiles, reqObj, response => {
this.runId = response.data;

View File

@ -187,7 +187,7 @@
<!--提取规则-->
<ms-api-extract @remove="remove" v-if="data.type==='Extract'" customizeStyle="margin-top: 0px" :extract="data" :node="node"/>
<!--API 导入 -->
<ms-api-component :request="data" @remove="remove" current-project="currentProject" v-if="data.type==='HTTPSamplerProxy'||data.type==='DubboSampler'||data.type==='JDBCSampler'||data.type==='TCPSampler'" :node="node"/>
<ms-api-component :request="data" @remove="remove" v-if="data.type==='HTTPSamplerProxy'||data.type==='DubboSampler'||data.type==='JDBCSampler'||data.type==='TCPSampler'" :node="node"/>
</template>
</span>
</el-tree>
@ -201,9 +201,9 @@
<div v-if="operatingElements.indexOf('HTTPSamplerProxy')>0 || operatingElements.indexOf('DubboSampler')>0 || operatingElements.indexOf('JDBCSampler')>0 || operatingElements.indexOf('TCPSampler')>0 ">
<el-button class="ms-right-buttion" size="small" style="color: #F56C6C;background-color: #FCF1F1" @click="apiListImport">+{{$t('api_test.automation.api_list_import')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('OT_IMPORT')>0">
<!--<div v-if="operatingElements.indexOf('OT_IMPORT')>0">
<el-button class="ms-right-buttion" size="small" style="color: #409EFF;background-color: #EEF5FE" @click="addComponent('OT_IMPORT')">+{{$t('api_test.automation.external_import')}}</el-button>
</div>
</div>-->
<div v-if="operatingElements.indexOf('ConstantTimer')>0">
<el-button class="ms-right-buttion" size="small" style="color: #67C23A;background-color: #F2F9EE" @click="addComponent('ConstantTimer')">+{{$t('api_test.automation.wait_controller')}}</el-button>
</div>
@ -239,13 +239,13 @@
<!--接口列表-->
<el-drawer :visible.sync="apiListVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('api_test.automation.api_list_import')" :modal="false" size="90%">
<ms-api-definition :visible="true" :currentRow="currentRow"/>
<!--<el-button style="float: right;margin: 20px" type="primary" @click="copyApi('REF')">{{$t('api_test.scenario.reference')}}</el-button>-->
<el-button style="float: right;margin: 20px 0px 0px " type="primary" @click="copyApi('Copy')">{{ $t('commons.copy') }}</el-button>
<el-button style="float: right;margin: 0px 20px 0px" type="primary" @click="copyApi('REF')">{{$t('api_test.scenario.reference')}}</el-button>
<el-button style="float: right;" type="primary" @click="copyApi('Copy')">{{ $t('commons.copy') }}</el-button>
</el-drawer>
<!--自定义接口-->
<el-drawer :visible.sync="customizeVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('api_test.automation.customize_req')" style="overflow: auto" :modal="false" size="90%">
<ms-api-customize :request="customizeRequest" @addCustomizeApi="addCustomizeApi" :current-project="currentProject"/>
<ms-api-customize :request="customizeRequest" @addCustomizeApi="addCustomizeApi" />
<!--<el-button style="float: right;margin: 20px" @click="addCustomizeApi">{{$t('commons.save')}}</el-button>-->
</el-drawer>
<!--场景导入 -->
@ -263,7 +263,7 @@
@runRefresh="runRefresh" ref="runTest"/>
<!-- 调试结果 -->
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProject.id"/>
<ms-api-report-detail :report-id="reportId" :debug="true" :currentProjectId="projectId"/>
</el-drawer>
<!--场景公共参数-->
@ -286,7 +286,7 @@
import MsApiComponent from "./ApiComponent";
import {ELEMENTS, ELEMENT_TYPE} from "./Setting";
import MsApiCustomize from "./ApiCustomize";
import {getUUID} from "@/common/js/utils";
import {getUUID, getCurrentProjectID} from "@/common/js/utils";
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
import MsAddTag from "./AddTag";
import MsRun from "./DebugRun";
@ -295,12 +295,10 @@
import MsApiReportDetail from "../report/ApiReportDetail";
import MsScenarioParameters from "./ScenarioParameters";
export default {
name: "EditApiScenario",
props: {
moduleOptions: Array,
currentProject: {},
currentScenario: {},
},
components: {
@ -326,6 +324,7 @@
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
apiScenarioModuleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
principal: [{required: true, message: this.$t('api_test.definition.request.responsible'), trigger: 'change'}],
},
environments: [],
tags: [],
@ -342,16 +341,18 @@
debugVisible: false,
customizeRequest: {protocol: "HTTP", type: "API", hashTree: [], referenced: 'Created', active: false},
operatingElements: [],
currentRow: {cases: [], apis: []},
currentRow: {cases: [], apis: [], referenced: true},
selectedTreeNode: undefined,
expandedNode: [],
scenarioDefinition: [],
path: "/api/automation/create",
debugData: {},
reportId: "",
projectId: "",
}
},
created() {
this.projectId = getCurrentProjectID();
this.operatingElements = ELEMENTS.get("ALL");
this.getMaintainerOptions();
this.refreshTags();
@ -361,7 +362,7 @@
watch: {},
methods: {
nodeClick(e) {
if (e.referenced != 'REF') {
if (e.referenced != 'REF' && e.referenced != 'Deleted') {
this.operatingElements = ELEMENTS.get(e.type);
} else {
this.operatingElements = [];
@ -513,14 +514,14 @@
},
openTagConfig() {
if (!this.currentProject) {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.tag.open(this.currentProject.id);
this.$refs.tag.open();
},
refreshTags() {
let obj = {projectId: this.currentProject.id};
let obj = {projectId: this.projectId};
let tagIds = [];
this.$post('/api/tag/list', obj, response => {
this.tags = response.data;
@ -553,12 +554,16 @@
this.$error(this.$t('api_test.environment.select_environment'));
return;
}
this.debugData = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition};
this.debugData = {
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
variables: this.currentScenario.variables, referenced: 'Created',
environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition
};
this.reportId = getUUID().substring(0, 8);
},
getEnvironments() {
if (this.currentProject) {
this.$get('/api/environment/list/' + this.currentProject.id, response => {
if (this.projectId) {
this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
@ -567,11 +572,11 @@
}
},
openEnvironmentConfig() {
if (!this.currentProject) {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
this.$refs.environmentConfig.open(this.projectId);
},
environmentConfigClose() {
this.getEnvironments();
@ -680,22 +685,28 @@
this.path = "/api/automation/update";
if (response.data.scenarioDefinition != null) {
let obj = JSON.parse(response.data.scenarioDefinition);
this.currentEnvironmentId = obj.environmentId;
this.scenarioDefinition = obj.hashTree;
if (obj) {
this.currentEnvironmentId = obj.environmentId;
this.currentScenario.variables = obj.variables;
this.scenarioDefinition = obj.hashTree;
}
}
}
})
}
},
setParameter() {
this.currentScenario.projectId = this.currentProject.id;
this.currentScenario.projectId = this.projectId;
if (!this.currentScenario.id) {
this.currentScenario.id = getUUID();
}
this.currentScenario.stepTotal = this.scenarioDefinition.length;
this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId);
// 便
let scenario = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition};
let scenario = {
id: this.currentScenario.id, name: this.currentScenario.name, variables: this.currentScenario.variables,
type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition
};
this.currentScenario.scenarioDefinition = scenario;
this.currentScenario.tagId = JSON.stringify(this.currentScenario.tagId);
if (this.currentModule != null) {

View File

@ -1,15 +1,15 @@
<template>
<ms-container>
<ms-aside-container>
<ms-api-scenario-module @selectModule="selectModule" @getApiModuleTree="initTree" @changeProject="changeProject"
<ms-api-scenario-module @selectModule="selectModule" @getApiModuleTree="initTree"
@refresh="refresh" @saveAsEdit="editScenario"/>
</ms-aside-container>
<ms-main-container>
<ms-api-scenario-list
:current-project="currentProject"
:current-module="currentModule"
@edit="editScenario"
@selection="setData"
:referenced="true"
ref="apiScenarioList"/>
<el-button style="float: right;margin: 10px" @click="importApiScenario" type="primary">{{ $t('api_test.scenario.reference') }}</el-button>
@ -36,7 +36,6 @@
return {
isHide: true,
activeName: 'default',
currentProject: null,
currentModule: null,
currentScenario: [],
currentScenarioIds: [],
@ -56,7 +55,6 @@
importApiScenario() {
let scenarios = [];
if (this.currentScenario) {
console.log(this.currentScenario)
this.currentScenario.forEach(item => {
let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'REF', resourceId: getUUID()};
scenarios.push(obj);
@ -85,9 +83,6 @@
initTree(data) {
this.moduleOptions = data;
},
changeProject(data) {
this.currentProject = data;
},
refresh(data) {
this.$refs.apiScenarioList.search(data);
},

View File

@ -2,10 +2,13 @@
<el-card>
<el-row>
<div>
<div class="el-step__icon is-text" :style="styleType" style="margin-right: 10px">
<div class="el-step__icon-inner">{{jsr223ProcessorData.index}}</div>
</div>
<el-button class="ms-left-buttion" size="small" :style="styleType" style="color: #B8741A;background-color: #F9F1EA">{{title}}</el-button>
<i class="icon el-icon-arrow-right" :class="{'is-active': this.jsr223ProcessorData.active}" @click="changeActive" style="margin-left: 20px"/>
<el-input size="small" v-model="jsr223ProcessorData.name" class="ms-api-header-select" style="width: 380px"/>
<el-button size="small" style="float: right" @click="remove">移除</el-button>
<el-button size="small" style="float: right" @click="remove">{{$t('commons.remove')}}</el-button>
</div>
</el-row>
<el-collapse-transition>

View File

@ -39,7 +39,8 @@ export default {
this.scenarioLoading = true;
this.scenarioRefs = [];
this.$post("/api/automation/getReference/", row, response => {
this.scenarioRefs = response.data;
this.scenarioRefs = response.data.scenarioList;
this.planRefs = response.data.testPlanList;
this.scenarioLoading = false;
})
},

View File

@ -11,28 +11,28 @@
</template>
<script>
import MsReferenceView from "@/business/components/api/automation/scenario/ReferenceView";
import MsReferenceView from "@/business/components/api/automation/scenario/ReferenceView";
export default {
name: "MsScenarioExtendButtons",
components: {MsReferenceView},
props: {
row: Object
},
methods: {
handleCommand(cmd) {
switch (cmd) {
case "ref":
this.$refs.viewRef.open(this.row);
break;
}
export default {
name: "MsScenarioExtendButtons",
components: {MsReferenceView},
props: {
row: Object
},
methods: {
handleCommand(cmd) {
switch (cmd) {
case "ref":
this.$refs.viewRef.open(this.row);
break;
}
},
}
}
}
</script>
<style scoped>
.scenario-ext-btn {
margin-left: 10px;
}
.scenario-ext-btn {
margin-left: 10px;
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<div v-if="isShow" style="float: right">
<el-dropdown placement="bottom" trigger="click" size="medium">
<div @click.stop class="show-more-btn">
<i class="el-icon-more ms-icon-more"/>
</div>
<el-dropdown-menu slot="dropdown" class="dropdown-menu-class">
<el-dropdown-item v-for="(btn,index) in buttons" :key="index" @click.native.stop="click(btn)">
{{btn.name}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
export default {
name: "ShowMoreBtn",
props: {
isShow: {
type: Boolean,
default: false
},
buttons: Array,
row: Object,
size: Number
},
methods: {
click(btn) {
if (btn.handleClick instanceof Function) {
btn.handleClick(this.row);
}
}
}
}
</script>
<style scoped>
.ms-icon-more {
margin-top: 15px;
transform: rotate(0deg);
}
.show-more-btn {
width: 20px;
height: 25px;
line-height: 25px;
}
.show-more-btn-title {
color: #696969;
background-color: #e2e2e2;
padding: 5px;
}
.dropdown-menu-class {
padding: 1px 0;
text-align: center;
}
</style>

View File

@ -0,0 +1,302 @@
<template>
<el-card class="table-card" v-loading="result.loading">
<template v-slot:header>
<ms-table-header :is-tester-permission="true" :condition.sync="condition"
@search="initTableData" :showCreate="false"
:title="$t('test_track.plan.test_plan')"/>
</template>
<el-table
border
class="adjust-table"
:data="tableData"
@filter-change="filter"
@sort-change="sort"
@select-all="select"
@select="select">
<el-table-column type="selection"/>
<el-table-column
prop="name"
:label="$t('commons.name')"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="userName"
:label="$t('test_track.plan.plan_principal')"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="status"
column-key="status"
:filters="statusFilters"
:label="$t('test_track.plan.plan_status')"
show-overflow-tooltip>
<template v-slot:default="scope">
<span @click.stop="clickt = 'stop'">
<el-dropdown class="test-case-status" @command="statusChange">
<span class="el-dropdown-link">
<plan-status-table-item :value="scope.row.status"/>
</span>
<el-dropdown-menu slot="dropdown" chang>
<el-dropdown-item :disabled="!isTestManagerOrTestUser" :command="{id: scope.row.id, status: 'Prepare'}">
{{ $t('test_track.plan.plan_status_prepare') }}
</el-dropdown-item>
<el-dropdown-item :disabled="!isTestManagerOrTestUser"
:command="{id: scope.row.id, status: 'Underway'}">
{{ $t('test_track.plan.plan_status_running') }}
</el-dropdown-item>
<el-dropdown-item :disabled="!isTestManagerOrTestUser"
:command="{id: scope.row.id, status: 'Completed'}">
{{ $t('test_track.plan.plan_status_completed') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</span>
</template>
</el-table-column>
<el-table-column
prop="stage"
column-key="stage"
:filters="stageFilters"
:label="$t('test_track.plan.plan_stage')"
show-overflow-tooltip>
<template v-slot:default="scope">
<plan-stage-table-item :stage="scope.row.stage"/>
</template>
</el-table-column>
<el-table-column
prop="projectName"
:label="$t('test_track.home.test_rate')"
min-width="100"
show-overflow-tooltip>
<template v-slot:default="scope">
<el-progress :percentage="scope.row.testRate"></el-progress>
</template>
</el-table-column>
<el-table-column
prop="projectName"
:label="$t('test_track.plan.plan_project')"
show-overflow-tooltip>
</el-table-column>
<el-table-column
sortable
prop="plannedStartTime"
:label="$t('test_track.plan.planned_start_time')"
show-overflow-tooltip>
<template v-slot:default="scope">
<span>{{ scope.row.plannedStartTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
sortable
prop="plannedEndTime"
:label="$t('test_track.plan.planned_end_time')"
show-overflow-tooltip>
<template v-slot:default="scope">
<span>{{ scope.row.plannedEndTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
sortable
prop="actualStartTime"
:label="$t('test_track.plan.actual_start_time')"
show-overflow-tooltip>
<template v-slot:default="scope">
<span>{{ scope.row.actualStartTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
sortable
prop="actualEndTime"
:label="$t('test_track.plan.actual_end_time')"
show-overflow-tooltip>
<template v-slot:default="scope">
<span>{{ scope.row.actualEndTime | timestampFormatDate }}</span>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="initTableData" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
<test-report-template-list @openReport="openReport" ref="testReportTemplateList"/>
<test-case-report-view @refresh="initTableData" ref="testCaseReportView"/>
<ms-delete-confirm :title="$t('test_track.plan.plan_delete')" @delete="_handleDelete" ref="deleteConfirm" :with-tip="enableDeleteTip">
{{$t('test_track.plan.plan_delete_tip')}}
</ms-delete-confirm>
<ms-dialog-footer style="float: right;margin: 20px"
@confirm="confirm">
</ms-dialog-footer>
</el-card>
</template>
<script>
import MsCreateBox from '../../../../settings/CreateBox';
import MsTablePagination from '../../../../../components/common/pagination/TablePagination';
import MsTableHeader from "../../../../common/components/MsTableHeader";
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
import MsTableOperator from "../../../../common/components/MsTableOperator";
import PlanStatusTableItem from "../../../../track/common/tableItems/plan/PlanStatusTableItem";
import PlanStageTableItem from "../../../../track/common/tableItems/plan/PlanStageTableItem";
import {_filter, _sort, checkoutTestManagerOrTestUser} from "@/common/js/utils";
import TestReportTemplateList from "../../../../track/plan/view/comonents/TestReportTemplateList";
import TestCaseReportView from "../../../../track/plan/view/comonents/report/TestCaseReportView";
import MsDeleteConfirm from "../../../../common/components/MsDeleteConfirm";
import {TEST_PLAN_CONFIGS} from "../../../../common/components/search/search-components";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
export default {
name: "TestPlanList",
components: {
MsDeleteConfirm,
TestCaseReportView,
TestReportTemplateList,
PlanStageTableItem,
PlanStatusTableItem,
MsTableOperator, MsTableOperatorButton, MsDialogFooter, MsTableHeader, MsCreateBox, MsTablePagination
},
data() {
return {
result: {},
selection: [],
enableDeleteTip: false,
queryPath: "/test/plan/list",
deletePath: "/test/plan/delete",
condition: {
components: TEST_PLAN_CONFIGS
},
currentPage: 1,
pageSize: 10,
isTestManagerOrTestUser: false,
total: 0,
tableData: [],
statusFilters: [
{text: this.$t('test_track.plan.plan_status_prepare'), value: 'Prepare'},
{text: this.$t('test_track.plan.plan_status_running'), value: 'Underway'},
{text: this.$t('test_track.plan.plan_status_completed'), value: 'Completed'}
],
stageFilters: [
{text: this.$t('test_track.plan.smoke_test'), value: 'smoke'},
{text: this.$t('test_track.plan.system_test'), value: 'system'},
{text: this.$t('test_track.plan.regression_test'), value: 'regression'},
],
}
},
watch: {
'$route'(to, from) {
if (to.path.indexOf("/track/plan/all") >= 0) {
this.initTableData();
}
}
},
created() {
this.projectId = this.$route.params.projectId;
this.isTestManagerOrTestUser = checkoutTestManagerOrTestUser();
this.initTableData();
},
methods: {
confirm() {
if (this.selection.length==0) {
this.$warning(this.$t("api_test.definition.request.test_plan_select"));
}
this.$emit('addTestPlan', this.selection);
},
select(selection) {
this.selection = selection.map(s => s.id);
this.$emit('selection', selection);
},
initTableData() {
if (this.planId) {
this.condition.planId = this.planId;
}
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
this.condition.nodeIds = this.selectNodeIds;
}
this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
for (let i = 0; i < this.tableData.length; i++) {
let path = "/test/plan/project";
this.$post(path, {planId: this.tableData[i].id}, res => {
let arr = res.data;
let projectName = arr.map(data => data.name).join("、");
let projectIds = arr.map(data => data.id);
this.$set(this.tableData[i], "projectName", projectName);
this.$set(this.tableData[i], "projectIds", projectIds);
})
}
});
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
testPlanCreate() {
this.$emit('openTestPlanEditDialog');
},
handleEdit(testPlan) {
this.$emit('testPlanEdit', testPlan);
},
statusChange(param) {
this.$post('/test/plan/edit', param, () => {
for (let i = 0; i < this.tableData.length; i++) {
if (this.tableData[i].id == param.id) {
this.tableData[i].status = param.status;
break;
}
}
});
},
handleDelete(testPlan) {
this.enableDeleteTip = testPlan.status === 'Underway' ? true : false;
this.$refs.deleteConfirm.open(testPlan);
},
_handleDelete(testPlan) {
let testPlanId = testPlan.id;
this.$post('/test/plan/delete/' + testPlanId, {}, () => {
this.initTableData();
this.$success(this.$t('commons.delete_success'));
// 广 head
TrackEvent.$emit(LIST_CHANGE);
});
},
intoPlan(row, event, column) {
this.$router.push('/track/plan/view/' + row.id);
},
filter(filters) {
_filter(filters, this.condition);
this.initTableData();
},
sort(column) {
_sort(column, this.condition);
this.initTableData();
},
openTestReportTemplate(data) {
this.$refs.testReportTemplateList.open(data.id);
},
openReport(planId, reportId) {
if (reportId) {
this.$refs.testCaseReportView.open(planId, reportId);
}
},
}
}
</script>
<style scoped>
.table-page {
padding-top: 20px;
margin-right: -9px;
float: right;
}
.el-table {
cursor: pointer;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<ms-container>
<ms-aside-container>
<ms-node-tree @selectModule="selectModule" @getApiModuleTree="initTree" @changeProject="changeProject" @changeProtocol="changeProtocol"
<ms-node-tree @selectModule="selectModule" @getApiModuleTree="initTree" @changeProtocol="changeProtocol"
@refresh="refresh" @saveAsEdit="editApi" @debug="debug" @exportAPI="exportAPI"/>
</ms-aside-container>
@ -18,50 +18,47 @@
<!-- 主框架列表 -->
<el-tabs v-model="apiDefaultTab" @edit="handleTabsEdit">
<el-tab-pane
:key="item.name"
v-for="(item) in apiTabs"
:label="item.title"
:closable="item.closable"
:name="item.name">
<!-- 列表集合 -->
<ms-api-list
v-if="item.type === 'list'"
:current-project="currentProject"
:current-protocol="currentProtocol"
:current-module="currentModule"
@editApi="editApi"
@handleCase="handleCase"
:visible="visible"
:currentRow="currentRow"
ref="apiList"/>
<el-tab-pane
:key="item.name"
v-for="(item) in apiTabs"
:label="item.title"
:closable="item.closable"
:name="item.name">
<!-- 列表集合 -->
<ms-api-list
v-if="item.type === 'list'"
:current-protocol="currentProtocol"
:current-module="currentModule"
@editApi="editApi"
@handleCase="handleCase"
:visible="visible"
:currentRow="currentRow"
ref="apiList"/>
<!-- 添加测试窗口-->
<div v-else-if="item.type=== 'add'" class="ms-api-div">
<ms-api-config @runTest="runTest" @saveApi="saveApi" :current-api="currentApi"
:currentProject="currentProject"
:currentProtocol="currentProtocol"
:moduleOptions="moduleOptions" ref="apiConfig"/>
</div>
<!-- 添加测试窗口-->
<div v-else-if="item.type=== 'add'" class="ms-api-div">
<ms-api-config @runTest="runTest" @saveApi="saveApi" :current-api="currentApi"
:currentProtocol="currentProtocol"
:moduleOptions="moduleOptions" ref="apiConfig"/>
</div>
<!-- 快捷调试 -->
<div v-else-if="item.type=== 'debug'" class="ms-api-div">
<ms-debug-http-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='HTTP'"/>
<ms-debug-jdbc-page :currentProtocol="currentProtocol" :currentProject="currentProject" @saveAs="editApi" v-if="currentProtocol==='SQL'"/>
<ms-debug-tcp-page :currentProtocol="currentProtocol" :currentProject="currentProject" @saveAs="editApi" v-if="currentProtocol==='TCP'"/>
<ms-debug-dubbo-page :currentProtocol="currentProtocol" :currentProject="currentProject" @saveAs="editApi" v-if="currentProtocol==='DUBBO'"/>
</div>
<!-- 快捷调试 -->
<div v-else-if="item.type=== 'debug'" class="ms-api-div">
<ms-debug-http-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='HTTP'"/>
<ms-debug-jdbc-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='SQL'"/>
<ms-debug-tcp-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='TCP'"/>
<ms-debug-dubbo-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='DUBBO'"/>
</div>
<!-- 测试-->
<div v-else-if="item.type=== 'test'" class="ms-api-div">
<ms-run-test-http-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" :currentProject="currentProject" v-if="currentProtocol==='HTTP'"/>
<ms-run-test-tcp-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" :currentProject="currentProject" v-if="currentProtocol==='TCP'"/>
<ms-run-test-sql-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" :currentProject="currentProject" v-if="currentProtocol==='SQL'"/>
<ms-run-test-dubbo-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" :currentProject="currentProject" v-if="currentProtocol==='DUBBO'"/>
</div>
</el-tab-pane>
</el-tabs>
<!-- 测试-->
<div v-else-if="item.type=== 'test'" class="ms-api-div">
<ms-run-test-http-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" v-if="currentProtocol==='HTTP'"/>
<ms-run-test-tcp-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" v-if="currentProtocol==='TCP'"/>
<ms-run-test-sql-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" v-if="currentProtocol==='SQL'"/>
<ms-run-test-dubbo-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" v-if="currentProtocol==='DUBBO'"/>
</div>
</el-tab-pane>
</el-tabs>
</ms-main-container>
@ -86,8 +83,7 @@
import MsRunTestTcpPage from "./components/runtest/RunTestTCPPage";
import MsRunTestSqlPage from "./components/runtest/RunTestSQLPage";
import MsRunTestDubboPage from "./components/runtest/RunTestDubboPage";
import {downloadFile, getCurrentUser, getUUID} from "@/common/js/utils";
import {downloadFile, getCurrentUser, getUUID, getCurrentProjectID} from "@/common/js/utils";
export default {
name: "ApiDefinition",
@ -120,7 +116,6 @@
return {
isHide: true,
apiDefaultTab: 'default',
currentProject: null,
currentProtocol: null,
currentModule: null,
currentApi: {},
@ -195,7 +190,7 @@
},
editApi(row) {
this.currentApi = row;
this.handleTabsEdit(row.name, "add");
this.handleTabsEdit(this.$t('api_test.definition.request.edit_api') + "-" + row.name, "add");
},
handleCase(testCase) {
this.currentApi = testCase;
@ -211,7 +206,7 @@
if (!this.$refs.apiList[0].tableData) {
return;
}
let obj = {projectName: this.currentProject.name, protocol: this.currentProtocol, data: this.$refs.apiList[0].tableData}
let obj = {projectName: getCurrentProjectID(), protocol: this.currentProtocol, data: this.$refs.apiList[0].tableData}
downloadFile("导出API.json", JSON.stringify(obj));
},
refresh(data) {
@ -221,7 +216,7 @@
for (let index in this.apiTabs) {
let tab = this.apiTabs[index];
if (tab.name === this.apiDefaultTab) {
tab.title = data.name;
tab.title = this.$t('api_test.definition.request.edit_api') + "-" + data.name;
break;
}
}
@ -238,9 +233,6 @@
initTree(data) {
this.moduleOptions = data;
},
changeProject(data) {
this.currentProject = data;
},
changeProtocol(data) {
this.currentProtocol = data;
}

View File

@ -82,8 +82,6 @@
<el-container style="padding-bottom: 200px">
<!-- 用例部分 -->
<el-main v-loading="loading" style="overflow: auto">
<div v-for="(item,index) in apiCaseList" :key="index">
<el-card style="margin-top: 5px" @click.native="selectTestCase(item,$event)">
@ -105,17 +103,22 @@
<el-col :span="10">
<i class="icon el-icon-arrow-right" :class="{'is-active': item.active}"
@click="active(item)"/>
<el-input v-if="item.type==='create'" size="small" v-model="item.name" :name="index" :key="index"
class="ms-api-header-select" style="width: 180px"
@blur="saveTestCase(item)"/>
<span v-else>
{{item.type!= 'create' ? item.name:''}}
<i class="el-icon-edit" style="cursor:pointer" @click="showInput(item)"/>
</span>
{{item.type!= 'create' ? item.name:''}}
<i class="el-icon-edit" style="cursor:pointer" @click="showInput(item)"/>
</span>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span> {{item.createTime | timestampFormatDate }}</span> {{item.createUser}} 创建
<span> {{item.updateTime | timestampFormatDate }}</span> {{item.updateUser}} 更新
<span>
{{item.createTime | timestampFormatDate }}
{{item.createUser}} {{$t('api_test.definition.request.create_info')}}
</span>
<span>
{{item.updateTime | timestampFormatDate }}
{{item.updateUser}} {{$t('api_test.definition.request.update_info')}}
</span>
</div>
</el-col>
@ -125,8 +128,8 @@
<ms-tip-button @click="copyCase(item)" :tip="$t('commons.copy')" icon="el-icon-document-copy"
size="mini" circle/>
<ms-tip-button @click="deleteCase(index,item)" :tip="$t('commons.delete')" icon="el-icon-delete"
size="mini"
circle/>
size="mini" circle/>
<ms-api-extend-btns :row="item"/>
</el-col>
<el-col :span="3">
@ -143,9 +146,9 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :is-read-only="isReadOnly" :headers="item.request.headers " :request="item.request" v-if="api.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="item.request" :currentProject="currentProject" v-if="api.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="item.request" :currentProject="currentProject" v-if="api.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="item.request" :currentProject="currentProject" v-if="api.protocol==='DUBBO'"/>
<ms-tcp-basis-parameters :request="item.request" v-if="api.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="item.request" v-if="api.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="item.request" v-if="api.protocol==='DUBBO'"/>
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)">
{{$t('commons.save')}}
@ -170,7 +173,7 @@
import MsTag from "../../../common/components/MsTag";
import MsTipButton from "../../../common/components/MsTipButton";
import MsApiRequestForm from "./request/http/ApiRequestForm";
import {downloadFile, getUUID} from "@/common/js/utils";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils";
import {parseEnvironment} from "../model/EnvironmentModel";
import ApiEnvironmentConfig from "./environment/ApiEnvironmentConfig";
import {PRIORITY, RESULT_MAP} from "../model/JsonData";
@ -180,6 +183,7 @@
import MsTcpBasisParameters from "./request/tcp/BasisParameters";
import MsDubboBasisParameters from "./request/dubbo/BasisParameters";
import MsDrawer from "../../../common/components/MsDrawer";
import MsApiExtendBtns from "./reference/ApiExtendBtns";
export default {
name: 'ApiCaseList',
@ -193,7 +197,8 @@
MsSqlBasisParameters,
MsTcpBasisParameters,
MsDubboBasisParameters,
MsRun
MsRun,
MsApiExtendBtns
},
props: {
api: {
@ -220,6 +225,7 @@
loading: false,
runData: [],
reportId: "",
projectId: "",
checkedCases: new Set(),
visible: false
@ -250,6 +256,7 @@
}
},
created() {
this.projectId = getCurrentProjectID();
this.getEnvironments();
if (this.createCase) {
this.sysAddition();
@ -413,6 +420,9 @@
test.request = JSON.parse(test.request);
}
this.apiCaseList = response.data;
if (this.apiCaseList.length == 0) {
this.addCase();
}
});
},
validate(row) {
@ -439,8 +449,8 @@
});
},
getEnvironments() {
if (this.currentProject) {
this.$get('/api/environment/list/' + this.currentProject.id, response => {
if (this.projectId) {
this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
@ -461,11 +471,11 @@
}
},
openEnvironmentConfig() {
if (!this.currentProject) {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
this.$refs.environmentConfig.open(this.projectId);
},
environmentChange(value) {
for (let i in this.environments) {

View File

@ -3,17 +3,16 @@
<div class="card-container">
<!-- HTTP 请求参数 -->
<ms-edit-complete-http-api @runTest="runTest" @saveApi="saveApi" :request="request" :response="response"
:basisData="currentApi" :moduleOptions="moduleOptions" :currentProject="currentProject" v-if="currentProtocol === 'HTTP'"/>
:basisData="currentApi" :moduleOptions="moduleOptions" v-if="currentProtocol === 'HTTP'"/>
<!-- TCP -->
<ms-edit-complete-tcp-api :request="request" @runTest="runTest" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
<ms-edit-complete-tcp-api :request="request" @runTest="runTest" @saveApi="saveApi" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'TCP'"/>
<!--DUBBO-->
<ms-edit-complete-dubbo-api :request="request" @runTest="runTest" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
<ms-edit-complete-dubbo-api :request="request" @runTest="runTest" @saveApi="saveApi" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'DUBBO'"/>
<!--SQL-->
<ms-edit-complete-sql-api :request="request" @runTest="runTest" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
<ms-edit-complete-sql-api :request="request" @runTest="runTest" @saveApi="saveApi" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'SQL'"/>
</div>
</template>
@ -24,10 +23,9 @@
import MsEditCompleteSqlApi from "./complete/EditCompleteSQLApi";
import {ResponseFactory, Body} from "../model/ApiTestModel";
import {getUUID} from "@/common/js/utils";
import {getUUID, getCurrentProjectID} from "@/common/js/utils";
import {createComponent, Request} from "./jmeter/components";
import Sampler from "./jmeter/components/sampler/sampler";
import HeaderManager from "./jmeter/components/configurations/header-manager";
import {WORKSPACE_ID} from '@/common/js/constants';
export default {
@ -39,16 +37,17 @@
request: Sampler,
config: {},
response: {},
projectId: "",
maintainerOptions: [],
}
},
props: {
currentApi: {},
moduleOptions: {},
currentProject: {},
currentProtocol: String,
},
created() {
this.projectId = getCurrentProjectID();
this.getMaintainerOptions();
switch (this.currentProtocol) {
case Request.TYPES.SQL:
@ -137,7 +136,7 @@
});
},
setParameters(data) {
data.projectId = this.currentProject.id;
data.projectId = this.projectId;
this.request.name = this.currentApi.name;
data.protocol = this.currentProtocol;
data.request = this.request;

View File

@ -72,9 +72,15 @@
<el-table-column :label="$t('commons.operating')" min-width="130" align="center">
<template v-slot:default="scope">
<el-button type="text" @click="editApi(scope.row)">编辑</el-button>
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">删除</el-button>
<div v-if="currentRow!=undefined && currentRow.referenced">
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
</div>
<div v-else>
<el-button type="text" @click="reductionApi(scope.row)" v-if="currentModule!=undefined && currentModule.id === 'gc'">恢复</el-button>
<el-button type="text" @click="editApi(scope.row)" v-else>编辑</el-button>
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
@ -82,7 +88,7 @@
:total="total"/>
</el-card>
<ms-api-case-list @refresh="initApiTable" :currentRow="currentRow"
:api="selectApi" :current-project="currentProject" ref="caseList"/>
:api="selectApi" ref="caseList"/>
</div>
</template>
@ -100,7 +106,8 @@
import MsContainer from "../../../common/components/MsContainer";
import MsBottomContainer from "./BottomContainer";
import ShowMoreBtn from "../../../../components/track/case/components/ShowMoreBtn";
import {API_METHOD_COLOUR, FILTER_MAP_1, FILTER_MAP_2} from "../model/JsonData";
import {API_METHOD_COLOUR} from "../model/JsonData";
import {getCurrentProjectID} from "@/common/js/utils";
export default {
name: "ApiList",
@ -129,11 +136,11 @@
currentPage: 1,
pageSize: 10,
total: 0,
projectId: "",
screenHeight: document.documentElement.clientHeight - 330,//
}
},
props: {
currentProject: Object,
currentProtocol: String,
currentModule: Object,
visible: {
@ -145,12 +152,10 @@
}
},
created: function () {
this.projectId = getCurrentProjectID();
this.initApiTable();
},
watch: {
currentProject() {
this.initApiTable();
},
currentModule() {
this.initApiTable();
},
@ -172,8 +177,8 @@
this.condition.moduleIds = this.currentModule.ids;
}
}
if (this.currentProject != null) {
this.condition.projectId = this.currentProject.id;
if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
@ -238,6 +243,15 @@
editApi(row) {
this.$emit('editApi', row);
},
reductionApi(row) {
row.status = 'Underway';
row.request = null;
row.response = null;
this.$fileUpload("/api/definition/update", null, [], row, () => {
this.$success(this.$t('commons.save_success'));
this.search();
});
},
handleDeleteBatch() {
if (this.currentModule != undefined && this.currentModule.id == "gc") {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {

View File

@ -1,11 +1,5 @@
<template>
<div v-loading="result.loading">
<select-menu
:data="projects"
:current-data="currentProject"
:title="$t('test_track.project')"
@dataChange="changeProject" style="margin-bottom: 20px"/>
<el-select style="width: 100px ;height: 30px" size="small" v-model="protocol" @change="changeProtocol">
<el-option
v-for="item in options"
@ -95,7 +89,7 @@
</el-tree>
<ms-add-basis-api :current-protocol="protocol" ref="basisApi"></ms-add-basis-api>
<api-import ref="apiImport" :project-id="currentProject.id" @refresh="refresh"/>
<api-import ref="apiImport" :project-id="projectId" @refresh="refresh"/>
</div>
@ -106,6 +100,7 @@
import SelectMenu from "../../../track/common/SelectMenu";
import {OPTIONS, DEFAULT_DATA} from "../model/JsonData";
import ApiImport from "./import/ApiImport";
import {getCurrentProjectID} from "@/common/js/utils";
export default {
name: 'MsApiModule',
@ -123,43 +118,36 @@
expandedNode: [],
filterText: "",
nextFlag: true,
currentProject: {},
projects: [],
projectId: "",
data: DEFAULT_DATA,
currentModule: {},
newLabel: ""
}
},
mounted() {
this.getProjects();
this.projectId = getCurrentProjectID();
this.changeProtocol();
},
watch: {
currentProject() {
this.getApiModuleTree();
this.$emit('changeProject', this.currentProject);
},
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
getApiModuleTree() {
if (this.currentProject) {
if (this.expandedNode.length === 0) {
this.expandedNode.push("root");
}
this.result = this.$get("/api/module/list/" + this.currentProject.id + "/" + this.protocol, response => {
if (response.data != undefined && response.data != null) {
this.data[1].children = response.data;
let moduleOptions = [];
this.data[1].children.forEach(node => {
this.buildNodePath(node, {path: ''}, moduleOptions);
});
this.$emit('getApiModuleTree', moduleOptions);
}
});
if (this.expandedNode.length === 0) {
this.expandedNode.push("root");
}
this.result = this.$get("/api/module/list/" + this.projectId + "/" + this.protocol, response => {
if (response.data != undefined && response.data != null) {
this.data[1].children = response.data;
let moduleOptions = [];
this.data[1].children.forEach(node => {
this.buildNodePath(node, {path: ''}, moduleOptions);
});
this.$emit('getApiModuleTree', moduleOptions);
}
});
},
handleCommand(e) {
switch (e) {
@ -364,7 +352,7 @@
},
//
editApiModule(node, data) {
if (!this.currentProject) {
if (!this.projectId) {
this.$error("$t('api_test.select_project')");
return;
}
@ -383,7 +371,7 @@
data.nodeIds = ids;
}
data.protocol = this.protocol;
data.projectId = this.currentProject.id;
data.projectId = this.projectId;
this.$post(url, data, () => {
this.$success(this.$t('commons.save_success'));
this.getApiModuleTree();
@ -420,20 +408,7 @@
return data.name.indexOf(value) !== -1;
},
addApi() {
this.$refs.basisApi.open(this.currentModule, this.currentProject.id);
},
//
changeProject(project) {
this.currentProject = project;
},
getProjects() {
let projectId;
this.$get("/project/listAll", (response) => {
this.projects = response.data;
if (this.projects.length > 0) {
this.currentProject = this.projects[0];
}
});
this.$refs.basisApi.open(this.currentModule, this.projectId);
},
nodeExpand(data) {
if (data.id) {

View File

@ -2,8 +2,11 @@
<div :style="customizeStyle" v-loading="loading">
<el-card>
<div>
<div class="el-step__icon is-text" style="color: #A30014;background-color: #F7E6E9;margin-right: 10px" v-if="assertions.index">
<div class="el-step__icon-inner">{{assertions.index}}</div>
</div>
<el-button class="ms-left-buttion" size="small" style="color: #A30014;background-color: #F7E6E9">{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<el-button size="small" style="float: right;margin-top: 0px" @click="remove">移除</el-button>
<el-button size="small" style="float: right;margin-top: 0px" @click="remove">{{$t('commons.remove')}}</el-button>
</div>
<div class="assertion-add">
<el-row :gutter="10">
@ -11,9 +14,6 @@
<el-select :disabled="isReadOnly" class="assertion-item" v-model="type"
:placeholder="$t('api_test.request.assertions.select_type')"
size="small">
<!--
<el-option :label="$t('api_test.request.assertions.text')" :value="options.TEXT"/>
-->
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
<el-option :label="'JSONPath'" :value="options.JSON_PATH"/>
<el-option :label="'XPath'" :value="options.XPATH2"/>
@ -22,10 +22,6 @@
</el-select>
</el-col>
<el-col :span="20">
<!--
<ms-api-assertion-text :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.TEXT"
:callback="after"/>
-->
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX"
:callback="after"/>
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath"
@ -41,24 +37,8 @@
</el-button>
</el-col>
</el-row>
<!--<div v-if="!scenario">-->
<!--<el-row :gutter="10" class="json-path-suggest-button">-->
<!--<el-link size="small" type="primary" @click="suggestJsonOpen" style="margin-right: 20px">-->
<!--{{ $t('api_test.request.assertions.json_path_suggest') }}-->
<!--</el-link>-->
<!--<el-link size="small" type="danger" @click="clearJson">-->
<!--{{ $t('api_test.request.assertions.json_path_clear') }}-->
<!--</el-link>-->
<!--</el-row>-->
<!--</div>-->
</div>
<!--<ms-api-jsonpath-suggest-list @addJsonpathSuggest="addJsonpathSuggest" :request="request"-->
<!--ref="jsonpathSuggestList"/>-->
<ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions" :reloadData="reloadData" style="margin-bottom: 20px"/>
</el-card>
</div>

View File

@ -102,5 +102,7 @@
</script>
<style scoped>
/deep/ .el-tabs__nav-wrap::after {
height: 0px;
}
</style>

View File

@ -80,7 +80,6 @@
basicForm: {},
httpVisible: false,
currentModule: {},
projectId: "",
maintainerOptions: [],
rule: {
name: [

View File

@ -22,10 +22,9 @@
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
<ms-basis-parameters :request="request"/>
</div>
</template>
<script>
@ -40,7 +39,6 @@
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
@ -57,10 +55,6 @@
validateApi() {
this.validated = false;
this.basisData.method = this.request.protocol;
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {

View File

@ -103,13 +103,9 @@
options: API_STATUS,
}
},
props: {moduleOptions: {}, currentProject: {}, request: {}, response: {}, basisData: {}},
props: {moduleOptions: {}, request: {}, response: {}, basisData: {}},
methods: {
runTest() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs['httpForm'].validate((valid) => {
if (valid) {
this.setParameter();
@ -132,10 +128,6 @@
this.httpForm.request.useEnvironment = undefined;
},
saveApi() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['httpForm'].validate((valid) => {
if (valid) {
this.setParameter();

View File

@ -21,7 +21,7 @@
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
<ms-basis-parameters :request="request"/>
</div>
</template>
@ -38,7 +38,6 @@
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
@ -55,10 +54,6 @@
},
validateApi() {
this.validated = false;
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {

View File

@ -21,7 +21,7 @@
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
<ms-basis-parameters :request="request"/>
</div>
@ -37,7 +37,6 @@
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
@ -57,10 +56,6 @@
validateApi() {
this.validated = false;
this.basisData.method = "TCP";
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {

View File

@ -12,7 +12,7 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- TCP 请求参数 -->
<ms-basis-parameters :request="request" :currentProject="currentProject" ref="requestForm"/>
<ms-basis-parameters :request="request" ref="requestForm"/>
<!-- TCP 请求返回数据 -->
@ -45,7 +45,6 @@
components: {MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun, MsBasisParameters},
props: {
currentProtocol: String,
currentProject: {},
scenario: Boolean,
},
data() {

View File

@ -50,8 +50,7 @@
import {getUUID, getCurrentUser} from "@/common/js/utils";
import MsResponseText from "../response/ResponseText";
import MsRun from "../Run";
import {createComponent, Request} from "../jmeter/components";
import HeaderManager from "../jmeter/components/configurations/header-manager";
import {createComponent} from "../jmeter/components";
import {REQ_METHOD} from "../../model/JsonData";
import MsRequestResultTail from "../response/RequestResultTail";

View File

@ -12,7 +12,7 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- JDBC 请求参数 -->
<ms-basis-parameters :request="request" @callback="runDebug" :currentProject="currentProject" ref="requestForm"/>
<ms-basis-parameters :request="request" @callback="runDebug" ref="requestForm"/>
<!-- JDBC 请求返回数据 -->
@ -47,7 +47,6 @@
components: {MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun, MsBasisParameters},
props: {
currentProtocol: String,
currentProject: {},
scenario: Boolean,
},
data() {

View File

@ -12,7 +12,7 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- TCP 请求参数 -->
<ms-basis-parameters :request="request" @callback="runDebug" :currentProject="currentProject" ref="requestForm"/>
<ms-basis-parameters :request="request" @callback="runDebug" ref="requestForm"/>
<!-- TCP 请求返回数据 -->
@ -46,7 +46,6 @@
components: {MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun, MsBasisParameters},
props: {
currentProtocol: String,
currentProject: {},
scenario: Boolean,
},
data() {

View File

@ -1,6 +1,9 @@
<template>
<div :style="customizeStyle">
<el-card>
<div class="el-step__icon is-text" style="color: #015478;background-color: #E6EEF2;margin-right: 10px" v-if="extract.index">
<div class="el-step__icon-inner">{{extract.index}}</div>
</div>
<el-button class="ms-left-buttion" size="small" style="color: #015478;background-color: #E6EEF2">{{$t('api_test.definition.request.extract_param')}}</el-button>
<el-button size="small" style="float: right;margin-top: 0px" @click="remove">移除</el-button>

View File

@ -37,6 +37,7 @@ export default class HTTPSamplerProxy extends Sampler {
this.rest = [];
this.files = [];
this.headers = [];
this.hashTree = [];
}
}

Some files were not shown because too many files have changed in this diff Show More