Merge remote-tracking branch 'origin/master'

This commit is contained in:
song.tianyang 2020-12-23 15:25:31 +08:00
commit 71686be223
48 changed files with 377 additions and 313 deletions

View File

@ -11,7 +11,7 @@ import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.DashboardTestDTO;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*;
@ -27,7 +27,7 @@ public class APIReportController {
@Resource
private APIReportService apiReportService;
@Resource
private CheckOwnerService checkOwnerService;
private CheckPermissionService checkPermissionService;
@GetMapping("recent/{count}")
public List<APIReportResult> recentTest(@PathVariable int count) {
@ -41,7 +41,7 @@ public class APIReportController {
@GetMapping("/list/{testId}/{goPage}/{pageSize}")
public Pager<List<APIReportResult>> listByTestId(@PathVariable String testId, @PathVariable int goPage, @PathVariable int pageSize) {
checkOwnerService.checkApiTestOwner(testId);
checkPermissionService.checkApiTestOwner(testId);
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, apiReportService.listByTestId(testId));

View File

@ -15,11 +15,13 @@ import io.metersphere.base.domain.ApiTest;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.*;
import io.metersphere.commons.utils.CronUtils;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.QueryScheduleRequest;
import io.metersphere.dto.ScheduleDao;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ScheduleService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
@ -27,7 +29,6 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
@ -46,7 +47,7 @@ public class APITestController {
@Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private CheckOwnerService checkownerService;
private CheckPermissionService checkownerService;
@Resource
private ApiTestCaseService apiTestCaseService;
@Resource

View File

@ -14,6 +14,7 @@ import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
@ -30,6 +31,8 @@ import java.util.List;
public class ApiDefinitionController {
@Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private CheckPermissionService checkPermissionService;
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<ApiDefinitionResult>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDefinitionRequest request) {
@ -41,18 +44,21 @@ public class ApiDefinitionController {
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER}, logical = Logical.OR)
public void create(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
checkPermissionService.checkReadOnlyUser();
apiDefinitionService.create(request, bodyFiles);
}
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER}, logical = Logical.OR)
public void update(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
checkPermissionService.checkReadOnlyUser();
apiDefinitionService.update(request, bodyFiles);
}
@GetMapping("/delete/{id}")
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER}, logical = Logical.OR)
public void delete(@PathVariable String id) {
checkPermissionService.checkReadOnlyUser();
apiDefinitionService.delete(id);
}

View File

@ -5,7 +5,7 @@ import io.metersphere.api.dto.definition.DragModuleRequest;
import io.metersphere.api.service.ApiModuleService;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*;
@ -21,17 +21,17 @@ public class ApiModuleController {
@Resource
ApiModuleService apiModuleService;
@Resource
private CheckOwnerService checkOwnerService;
private CheckPermissionService checkPermissionService;
@GetMapping("/list/{projectId}/{protocol}")
public List<ApiModuleDTO> getNodeByProjectId(@PathVariable String projectId,@PathVariable String protocol) {
checkOwnerService.checkProjectOwner(projectId);
checkPermissionService.checkProjectOwner(projectId);
return apiModuleService.getNodeTreeByProjectId(projectId,protocol);
}
@GetMapping("/list/plan/{planId}/{protocol}")
public List<ApiModuleDTO> getNodeByPlanId(@PathVariable String planId, @PathVariable String protocol) {
checkOwnerService.checkTestPlanOwner(planId);
checkPermissionService.checkTestPlanOwner(planId);
return apiModuleService.getNodeByPlanId(planId, protocol);
}

View File

@ -5,14 +5,13 @@ import io.metersphere.api.dto.automation.DragApiScenarioModuleRequest;
import io.metersphere.api.service.ApiScenarioModuleService;
import io.metersphere.base.domain.ApiScenarioModule;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import javax.annotation.Resource;
import java.util.List;
@RequestMapping("/api/automation/module")
@RestController
@ -22,11 +21,11 @@ public class ApiScenarioModuleController {
@Resource
ApiScenarioModuleService apiScenarioModuleService;
@Resource
private CheckOwnerService checkOwnerService;
private CheckPermissionService checkPermissionService;
@GetMapping("/list/{projectId}")
public List<ApiScenarioModuleDTO> getNodeByProjectId(@PathVariable String projectId) {
checkOwnerService.checkProjectOwner(projectId);
checkPermissionService.checkProjectOwner(projectId);
return apiScenarioModuleService.getNodeTreeByProjectId(projectId);
}
@ -44,7 +43,7 @@ public class ApiScenarioModuleController {
@GetMapping("/list/plan/{planId}")
public List<ApiScenarioModuleDTO> getNodeByPlanId(@PathVariable String planId) {
checkOwnerService.checkTestPlanOwner(planId);
checkPermissionService.checkTestPlanOwner(planId);
return apiScenarioModuleService.getNodeByPlanId(planId);
}

View File

@ -3,7 +3,7 @@ package io.metersphere.api.controller;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*;
@ -19,11 +19,11 @@ public class ApiTestEnvironmentController {
@Resource
ApiTestEnvironmentService apiTestEnvironmentService;
@Resource
private CheckOwnerService checkOwnerService;
private CheckPermissionService checkPermissionService;
@GetMapping("/list/{projectId}")
public List<ApiTestEnvironmentWithBLOBs> list(@PathVariable String projectId) {
checkOwnerService.checkProjectOwner(projectId);
checkPermissionService.checkProjectOwner(projectId);
return apiTestEnvironmentService.list(projectId);
}

View File

@ -15,6 +15,8 @@ public class RunDefinitionRequest {
private String reportId;
private String name;
private String type;
private String projectId;

View File

@ -119,9 +119,15 @@ public class MsHTTPSamplerProxy extends MsTestElement {
sampler.setPort(config.getConfig().getHttpConfig().getPort());
sampler.setProtocol(config.getConfig().getHttpConfig().getProtocol());
url = config.getConfig().getHttpConfig().getProtocol() + "://" + config.getConfig().getHttpConfig().getSocket();
// 补充如果是完整URL 则用自身URL
boolean isUrl = false;
if (StringUtils.isNotEmpty(this.getUrl()) && isURL(this.getUrl())) {
url = this.getUrl();
isUrl = true;
}
URL urlObject = new URL(url);
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
if (StringUtils.isNotBlank(this.getPath())) {
if (StringUtils.isNotBlank(this.getPath()) && !isUrl) {
envPath += this.getPath();
}
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
@ -243,6 +249,15 @@ public class MsHTTPSamplerProxy extends MsTestElement {
tree.add(headerManager);
}
public boolean isURL(String str) {
//转换为小写
try {
new URL(str);
return true;
} catch (Exception e) {
return false;
}
}
private boolean isRest() {
return this.getRest().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).toArray().length > 0;

View File

@ -98,11 +98,14 @@ public class Body {
return StringUtils.equals(type, XML);
}
public boolean isWwwFROM() {
return StringUtils.equals(type, WWW_FROM);
public void initKvs() {
this.kvs = new ArrayList<>();
this.kvs.add(new KeyValue());
}
public boolean isFromData() {
return StringUtils.equals(type, FORM_DATA);
public void initBinary() {
this.binary = new ArrayList<>();
this.binary.add(new KeyValue());
}
}

View File

@ -15,7 +15,7 @@ public class KeyValue {
private List<BodyFile> files;
private String description;
private String contentType;
private boolean enable;
private boolean enable = true;
private boolean encode = true;
private boolean required;

View File

@ -20,6 +20,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@ -72,7 +73,7 @@ public abstract class ApiImportAbstractParser implements ApiImportParser {
protected ApiDefinitionResult buildApiDefinition(String id, String name, String path, String method) {
ApiDefinitionResult apiDefinition = new ApiDefinitionResult();
apiDefinition.setName(name);
apiDefinition.setPath(path);
apiDefinition.setPath(formatPath(path));
apiDefinition.setProtocol(RequestType.HTTP);
apiDefinition.setMethod(method);
apiDefinition.setId(id);
@ -81,17 +82,34 @@ public abstract class ApiImportAbstractParser implements ApiImportParser {
return apiDefinition;
}
private String formatPath(String url) {
try {
URL urlObject = new URL(url);
StringBuffer pathBuffer = new StringBuffer(urlObject.getPath());
if (StringUtils.isNotEmpty(urlObject.getQuery())) {
pathBuffer.append("?").append(urlObject.getQuery());
}
return pathBuffer.toString();
} catch (Exception ex) {
return url;
}
}
protected MsHTTPSamplerProxy buildRequest(String name, String path, String method) {
MsHTTPSamplerProxy request = new MsHTTPSamplerProxy();
request.setName(name);
request.setPath(path);
// 路径去掉域名/IP 地址保留方法名称及参数
request.setPath(formatPath(path));
request.setMethod(method);
request.setProtocol(RequestType.HTTP);
request.setId(UUID.randomUUID().toString());
request.setHeaders(new ArrayList<>());
request.setArguments(new ArrayList<>());
request.setRest(new ArrayList<>());
request.setBody(new Body());
Body body = new Body();
body.initKvs();
body.initBinary();
request.setBody(body);
return request;
}

View File

@ -289,6 +289,7 @@ public class ApiAutomationService {
});
scenario.setVariables(variables);
}
group.setEnableCookieShare(scenario.isEnableCookieShare());
LinkedList<MsTestElement> scenarios = new LinkedList<>();
scenarios.add(scenario);
group.setHashTree(scenarios);

View File

@ -16,10 +16,13 @@ import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper;
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.DateUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.i18n.Translator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -28,10 +31,7 @@ import sun.security.util.Cache;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
@ -55,6 +55,13 @@ public class ApiScenarioReportService {
MSException.throwException(Translator.get("api_report_is_null"));
}
APIScenarioReportResult report = (APIScenarioReportResult) obj;
if (CollectionUtils.isNotEmpty(result.getScenarios())) {
try {
report.setName(result.getScenarios().get(0).getName() + "-" + DateUtils.getTimeString(System.currentTimeMillis()));
} catch (Exception e) {
LogUtil.error(e.getMessage());
}
}
// report detail
ApiScenarioReportDetail detail = new ApiScenarioReportDetail();
detail.setReportId(result.getTestId());
@ -72,7 +79,9 @@ public class ApiScenarioReportService {
}
report.setContent(new String(detail.getContent(), StandardCharsets.UTF_8));
this.save(report, runMode);
cache.put(report.getId(), report);
if (!report.getTriggerMode().equals(ReportTriggerMode.SCHEDULE.name())) {
cache.put(report.getId(), report);
}
}
/**

View File

@ -9,7 +9,7 @@ import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.ProjectRequest;
import io.metersphere.dto.ProjectDTO;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ProjectService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
@ -24,7 +24,7 @@ public class ProjectController {
@Resource
private ProjectService projectService;
@Resource
private CheckOwnerService checkOwnerService;
private CheckPermissionService checkPermissionService;
@GetMapping("/listAll")
public List<ProjectDTO> listAll() {
@ -74,7 +74,7 @@ public class ProjectController {
@GetMapping("/delete/{projectId}")
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER,}, logical = Logical.OR)
public void deleteProject(@PathVariable(value = "projectId") String projectId) {
checkOwnerService.checkProjectOwner(projectId);
checkPermissionService.checkProjectOwner(projectId);
projectService.deleteProject(projectId);
}

View File

@ -1,9 +1,7 @@
package io.metersphere.job.sechedule;
import io.metersphere.api.dto.SaveAPITestRequest;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.service.APITestService;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.ScheduleGroup;
@ -56,7 +54,7 @@ public class ApiScenarioTestJob extends MsScheduleJob {
request.setId(id);
request.setReportId(id);
request.setProjectId(projectID);
request.setTriggerMode(ReportTriggerMode.MANUAL.name());
request.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
request.setExecuteType(ExecuteType.Completed.name());
request.setScenarioIds(this.scenarioIds);
request.setReportUserID(this.userId);

View File

@ -14,7 +14,7 @@ import io.metersphere.dto.DashboardTestDTO;
import io.metersphere.dto.LoadTestDTO;
import io.metersphere.dto.ScheduleDao;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.FileService;
import io.metersphere.track.request.testplan.*;
import org.apache.shiro.authz.annotation.Logical;
@ -37,7 +37,7 @@ public class PerformanceTestController {
@Resource
private FileService fileService;
@Resource
private CheckOwnerService checkOwnerService;
private CheckPermissionService checkPermissionService;
@GetMapping("recent/{count}")
public List<LoadTestDTO> recentTestPlans(@PathVariable int count) {
@ -59,14 +59,14 @@ public class PerformanceTestController {
@GetMapping("/list/{projectId}")
public List<LoadTest> list(@PathVariable String projectId) {
checkOwnerService.checkProjectOwner(projectId);
checkPermissionService.checkProjectOwner(projectId);
return performanceTestService.getLoadTestByProjectId(projectId);
}
@GetMapping("/state/get/{testId}")
public LoadTest listByTestId(@PathVariable String testId) {
checkOwnerService.checkPerformanceTestOwner(testId);
checkPermissionService.checkPerformanceTestOwner(testId);
return performanceTestService.getLoadTestBytestId(testId);
}
@ -75,6 +75,7 @@ public class PerformanceTestController {
@RequestPart("request") SaveTestPlanRequest request,
@RequestPart(value = "file") List<MultipartFile> files
) {
checkPermissionService.checkReadOnlyUser();
return performanceTestService.save(request, files);
}
@ -83,37 +84,39 @@ public class PerformanceTestController {
@RequestPart("request") EditTestPlanRequest request,
@RequestPart(value = "file", required = false) List<MultipartFile> files
) {
checkOwnerService.checkPerformanceTestOwner(request.getId());
checkPermissionService.checkReadOnlyUser();
checkPermissionService.checkPerformanceTestOwner(request.getId());
return performanceTestService.edit(request, files);
}
@GetMapping("/get/{testId}")
public LoadTestDTO get(@PathVariable String testId) {
checkOwnerService.checkPerformanceTestOwner(testId);
checkPermissionService.checkPerformanceTestOwner(testId);
return performanceTestService.get(testId);
}
@GetMapping("/get-advanced-config/{testId}")
public String getAdvancedConfiguration(@PathVariable String testId) {
checkOwnerService.checkPerformanceTestOwner(testId);
checkPermissionService.checkPerformanceTestOwner(testId);
return performanceTestService.getAdvancedConfiguration(testId);
}
@GetMapping("/get-load-config/{testId}")
public String getLoadConfiguration(@PathVariable String testId) {
checkOwnerService.checkPerformanceTestOwner(testId);
checkPermissionService.checkPerformanceTestOwner(testId);
return performanceTestService.getLoadConfiguration(testId);
}
@GetMapping("/get-jmx-content/{testId}")
public String getJmxContent(@PathVariable String testId) {
checkOwnerService.checkPerformanceTestOwner(testId);
checkPermissionService.checkPerformanceTestOwner(testId);
return performanceTestService.getJmxContent(testId);
}
@PostMapping("/delete")
public void delete(@RequestBody DeleteTestPlanRequest request) {
checkOwnerService.checkPerformanceTestOwner(request.getId());
checkPermissionService.checkReadOnlyUser();
checkPermissionService.checkPerformanceTestOwner(request.getId());
performanceTestService.delete(request);
}
@ -129,7 +132,7 @@ public class PerformanceTestController {
@GetMapping("/file/metadata/{testId}")
public List<FileMetadata> getFileMetadata(@PathVariable String testId) {
checkOwnerService.checkPerformanceTestOwner(testId);
checkPermissionService.checkPerformanceTestOwner(testId);
return fileService.getFileMetadataByTestId(testId);
}

View File

@ -9,7 +9,6 @@ import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@ -18,7 +17,7 @@ import java.util.Set;
import java.util.stream.Collectors;
@Service
public class CheckOwnerService {
public class CheckPermissionService {
@Resource
private ProjectMapper projectMapper;
@Resource
@ -32,6 +31,20 @@ public class CheckOwnerService {
@Resource
private ExtTestCaseReviewMapper extTestCaseReviewMapper;
public void checkReadOnlyUser() {
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
Set<String> collect = Objects.requireNonNull(SessionUtils.getUser()).getUserRoles().stream()
.filter(ur ->
StringUtils.equals(ur.getRoleId(), RoleConstants.TEST_VIEWER))
.map(UserRole::getSourceId)
.filter(sourceId -> StringUtils.equals(currentWorkspaceId, sourceId))
.collect(Collectors.toSet());
if (CollectionUtils.isNotEmpty(collect)) {
throw new RuntimeException(Translator.get("check_owner_read_only"));
}
}
public void checkProjectOwner(String projectId) {
Set<String> workspaceIds = getUserRelatedWorkspaceIds();
Project project = projectMapper.selectByPrimaryKey(projectId);
@ -42,7 +55,7 @@ public class CheckOwnerService {
return;
}
if (!workspaceIds.contains(project.getWorkspaceId())) {
throw new UnauthorizedException(Translator.get("check_owner_project"));
throw new RuntimeException(Translator.get("check_owner_project"));
}
}
@ -67,7 +80,7 @@ public class CheckOwnerService {
int result = extApiTestMapper.checkApiTestOwner(testId, workspaceIds);
if (result == 0) {
throw new UnauthorizedException(Translator.get("check_owner_test"));
throw new RuntimeException(Translator.get("check_owner_test"));
}
}
@ -83,7 +96,7 @@ public class CheckOwnerService {
int result = extLoadTestMapper.checkLoadTestOwner(testId, workspaceIds);
if (result == 0) {
throw new UnauthorizedException(Translator.get("check_owner_test"));
throw new RuntimeException(Translator.get("check_owner_test"));
}
}
@ -95,7 +108,7 @@ public class CheckOwnerService {
int result = extTestCaseMapper.checkIsHave(caseId, workspaceIds);
if (result == 0) {
throw new UnauthorizedException(Translator.get("check_owner_case"));
throw new RuntimeException(Translator.get("check_owner_case"));
}
}
@ -106,7 +119,7 @@ public class CheckOwnerService {
}
int result = extTestPlanMapper.checkIsHave(planId, workspaceIds);
if (result == 0) {
throw new UnauthorizedException(Translator.get("check_owner_plan"));
throw new RuntimeException(Translator.get("check_owner_plan"));
}
}
@ -117,7 +130,7 @@ public class CheckOwnerService {
}
int result = extTestCaseReviewMapper.checkIsHave(reviewId, workspaceIds);
if (result == 0) {
throw new UnauthorizedException(Translator.get("check_owner_review"));
throw new RuntimeException(Translator.get("check_owner_review"));
}
}
}

View File

@ -11,7 +11,7 @@ import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.excel.domain.ExcelResponse;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.FileService;
import io.metersphere.track.dto.TestCaseDTO;
import io.metersphere.track.request.testcase.EditTestCaseRequest;
@ -39,7 +39,7 @@ public class TestCaseController {
@Resource
TestCaseService testCaseService;
@Resource
private CheckOwnerService checkOwnerService;
private CheckPermissionService checkPermissionService;
@Resource
private FileService fileService;
@ -51,7 +51,7 @@ public class TestCaseController {
@GetMapping("/list/{projectId}")
public List<TestCaseDTO> list(@PathVariable String projectId) {
checkOwnerService.checkProjectOwner(projectId);
checkPermissionService.checkProjectOwner(projectId);
QueryTestCaseRequest request = new QueryTestCaseRequest();
request.setProjectId(projectId);
return testCaseService.listTestCase(request);
@ -94,13 +94,13 @@ public class TestCaseController {
@GetMapping("/get/{testCaseId}")
public TestCaseWithBLOBs getTestCase(@PathVariable String testCaseId) {
checkOwnerService.checkTestCaseOwner(testCaseId);
checkPermissionService.checkTestCaseOwner(testCaseId);
return testCaseService.getTestCase(testCaseId);
}
@GetMapping("/project/{testCaseId}")
public Project getProjectByTestCaseId(@PathVariable String testCaseId) {
checkOwnerService.checkTestCaseOwner(testCaseId);
checkPermissionService.checkTestCaseOwner(testCaseId);
return testCaseService.getProjectByTestCaseId(testCaseId);
}
@ -119,14 +119,14 @@ public class TestCaseController {
@PostMapping("/delete/{testCaseId}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public int deleteTestCase(@PathVariable String testCaseId) {
checkOwnerService.checkTestCaseOwner(testCaseId);
checkPermissionService.checkTestCaseOwner(testCaseId);
return testCaseService.deleteTestCase(testCaseId);
}
@PostMapping("/import/{projectId}/{userId}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public ExcelResponse testCaseImport(MultipartFile file, @PathVariable String projectId, @PathVariable String userId) {
checkOwnerService.checkProjectOwner(projectId);
checkPermissionService.checkProjectOwner(projectId);
return testCaseService.testCaseImport(file, projectId, userId);
}

View File

@ -2,7 +2,7 @@ package io.metersphere.track.controller;
import io.metersphere.base.domain.TestCaseNode;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.track.dto.TestCaseNodeDTO;
import io.metersphere.track.request.testcase.DragNodeRequest;
import io.metersphere.track.request.testcase.QueryNodeRequest;
@ -22,11 +22,11 @@ public class TestCaseNodeController {
@Resource
TestCaseNodeService testCaseNodeService;
@Resource
private CheckOwnerService checkOwnerService;
private CheckPermissionService checkPermissionService;
@GetMapping("/list/{projectId}")
public List<TestCaseNodeDTO> getNodeByProjectId(@PathVariable String projectId) {
checkOwnerService.checkProjectOwner(projectId);
checkPermissionService.checkProjectOwner(projectId);
return testCaseNodeService.getNodeTreeByProjectId(projectId);
}
@ -43,13 +43,13 @@ public class TestCaseNodeController {
@GetMapping("/list/plan/{planId}")
public List<TestCaseNodeDTO> getNodeByPlanId(@PathVariable String planId) {
checkOwnerService.checkTestPlanOwner(planId);
checkPermissionService.checkTestPlanOwner(planId);
return testCaseNodeService.getNodeByPlanId(planId);
}
@GetMapping("/list/review/{reviewId}")
public List<TestCaseNodeDTO> getNodeByReviewId(@PathVariable String reviewId) {
checkOwnerService.checkTestReviewOwner(reviewId);
checkPermissionService.checkTestReviewOwner(reviewId);
return testCaseNodeService.getNodeByReviewId(reviewId);
}

View File

@ -9,7 +9,7 @@ import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.track.dto.TestCaseReviewDTO;
import io.metersphere.track.dto.TestReviewDTOWithMetric;
import io.metersphere.track.request.testreview.QueryCaseReviewRequest;
@ -35,7 +35,7 @@ public class TestCaseReviewController {
@Resource
TestReviewProjectService testReviewProjectService;
@Resource
CheckOwnerService checkOwnerService;
CheckPermissionService checkPermissionService;
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<TestCaseReviewDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryCaseReviewRequest request) {
@ -75,7 +75,7 @@ public class TestCaseReviewController {
@GetMapping("/delete/{reviewId}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void deleteCaseReview(@PathVariable String reviewId) {
checkOwnerService.checkTestReviewOwner(reviewId);
checkPermissionService.checkTestReviewOwner(reviewId);
testCaseReviewService.deleteCaseReview(reviewId);
}
@ -107,14 +107,14 @@ public class TestCaseReviewController {
@GetMapping("/get/{reviewId}")
public TestCaseReview getTestReview(@PathVariable String reviewId) {
checkOwnerService.checkTestReviewOwner(reviewId);
checkPermissionService.checkTestReviewOwner(reviewId);
return testCaseReviewService.getTestReview(reviewId);
}
@PostMapping("/edit/status/{reviewId}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void editTestPlanStatus(@PathVariable String reviewId) {
checkOwnerService.checkTestReviewOwner(reviewId);
checkPermissionService.checkTestReviewOwner(reviewId);
testCaseReviewService.editTestReviewStatus(reviewId);
}

View File

@ -8,7 +8,7 @@ import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.service.CheckOwnerService;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.track.dto.TestCaseReportMetricDTO;
import io.metersphere.track.dto.TestPlanDTO;
import io.metersphere.track.dto.TestPlanDTOWithMetric;
@ -34,7 +34,7 @@ public class TestPlanController {
@Resource
TestPlanProjectService testPlanProjectService;
@Resource
CheckOwnerService checkOwnerService;
CheckPermissionService checkPermissionService;
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<TestPlanDTOWithMetric>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanRequest request) {
@ -73,7 +73,7 @@ public class TestPlanController {
@PostMapping("/get/{testPlanId}")
public TestPlan getTestPlan(@PathVariable String testPlanId) {
checkOwnerService.checkTestPlanOwner(testPlanId);
checkPermissionService.checkTestPlanOwner(testPlanId);
return testPlanService.getTestPlan(testPlanId);
}
@ -92,14 +92,14 @@ public class TestPlanController {
@PostMapping("/edit/status/{planId}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void editTestPlanStatus(@PathVariable String planId) {
checkOwnerService.checkTestPlanOwner(planId);
checkPermissionService.checkTestPlanOwner(planId);
testPlanService.editTestPlanStatus(planId);
}
@PostMapping("/delete/{testPlanId}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public int deleteTestPlan(@PathVariable String testPlanId) {
checkOwnerService.checkTestPlanOwner(testPlanId);
checkPermissionService.checkTestPlanOwner(testPlanId);
return testPlanService.deleteTestPlan(testPlanId);
}

View File

@ -164,6 +164,7 @@ check_owner_case=The current user does not have permission to operate this use c
check_owner_plan=The current user does not have permission to operate this plan
check_owner_review=The current user does not have permission to operate this review
check_owner_comment=The current user does not have permission to manipulate this comment
check_owner_read_only=The current user in this workspace is a read-only user
upload_content_is_null=Imported content is empty
test_plan_notification=Test plan notification
task_defect_notification=Task defect notification

View File

@ -165,6 +165,7 @@ check_owner_case=当前用户没有操作此用例的权限
check_owner_plan=当前用户没有操作此计划的权限
check_owner_review=当前用户没有操作此评审的权限
check_owner_comment=当前用户没有操作此评论的权限
check_owner_read_only=当前用户在此工作空间为只读用户
upload_content_is_null=导入内容为空
test_plan_notification=测试计划通知
task_defect_notification=缺陷任务通知

View File

@ -166,6 +166,7 @@ check_owner_case=當前用戶沒有操作此用例的權限
check_owner_plan=當前用戶沒有操作此計劃的權限
check_owner_review=當前用戶沒有操作此評審的權限
check_owner_comment=當前用戶沒有操作此評論的權限
check_owner_read_only=當前用戶在此工作空間為只讀用戶
upload_content_is_null=導入內容為空
test_plan_notification=測試計畫通知
task_defect_notification=缺陷任務通知

View File

@ -69,7 +69,7 @@
import MsContainer from "../../../common/components/MsContainer";
import MsMainContainer from "../../../common/components/MsMainContainer";
import MsApiReportStatus from "./ApiReportStatus";
import {_filter, _sort} from "@/common/js/utils";
import {_filter, _sort,getCurrentProjectID} from "@/common/js/utils";
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
import ReportTriggerModeItem from "../../../common/tableItem/ReportTriggerModeItem";
import {REPORT_CONFIGS} from "../../../common/components/search/search-components";
@ -130,6 +130,7 @@
if (this.testId !== 'all') {
this.condition.testId = this.testId;
}
this.condition.projectId = getCurrentProjectID();
let url = "/api/scenario/report/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => {
let data = response.data;

View File

@ -19,19 +19,14 @@
<el-tabs v-model="activeName" v-show="isActive" v-if="hasSub">
<el-tab-pane :label="$t('api_report.sub_result')" name="sub">
<ms-request-sub-result class="sub-result" v-for="(sub, index) in request.subRequestResults"
:key="index" :request="sub"/>
:key="index" :indexNumber="index" :request="sub"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_report.request_result')" name="result">
<ms-request-metric :request="request"/>
<ms-request-text :request="request"/>
<br>
<ms-response-text :request-type="requestType" :response="request.responseResult"/>
<ms-response-text :request-type="requestType" :response="request.responseResult" :request="request"/>
</el-tab-pane>
</el-tabs>
<div v-else>
<ms-request-text v-if="isCodeEditAlive" :request="request"/>
<br>
<ms-response-text :request-type="requestType" v-if="isCodeEditAlive" :response="request.responseResult"/>
<ms-response-text :request-type="requestType" v-if="isCodeEditAlive" :response="request.responseResult" :request="request"/>
</div>
</div>
</el-collapse-transition>

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="14" v-if="indexNumber!=undefined">
<el-col :span="6" 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,7 +14,16 @@
{{ request.name }}
</div>
</el-col>
<el-col :span="2">
<div>
{{ request.method }}
</div>
</el-col>
<el-col :span="6">
<div class="url">
{{ request.url }}
</div>
</el-col>
<el-col :span="5">
<el-tooltip effect="dark" :content="request.responseResult.responseCode" placement="bottom" :open-delay="800">
<div class="url" style="color: #5daf34">{{ request.responseResult.responseCode }}</div>

View File

@ -1,18 +1,19 @@
<template>
<div class="text-container">
<div @click="active" class="collapse">
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
{{ $t('api_report.response') }}
</div>
<el-collapse-transition>
<el-tabs v-model="activeName" v-show="isActive">
<el-tab-pane :class="'body-pane'" label="Body" name="body" class="pane">
<el-tab-pane :label="$t('api_test.definition.request.response_header')" name="headers" class="pane">
<pre>{{ response.headers }}</pre>
</el-tab-pane>
<el-tab-pane :class="'body-pane'" :label="$t('api_test.definition.request.response_body')" name="body" class="pane">
<ms-sql-result-table v-if="isSqlType" :body="response.body"/>
<ms-code-edit v-if="!isSqlType" :mode="mode" :read-only="true" :data="response.body" :modes="modes" ref="codeEdit"/>
</el-tab-pane>
<el-tab-pane label="Headers" name="headers" class="pane">
<pre>{{ response.headers }}</pre>
<el-tab-pane :label="$t('api_test.definition.request.console')" name="console" class="pane">
<pre>{{response.console}}</pre>
</el-tab-pane>
<el-tab-pane :label="$t('api_report.assertions')" name="assertions" class="pane assertions">
<ms-assertion-results :assertions="response.assertions"/>
</el-tab-pane>
@ -21,79 +22,97 @@
<pre>{{response.vars}}</pre>
</el-tab-pane>
<el-tab-pane :label="$t('api_report.request_body')" name="request_body" class="pane">
<div class="ms-div">
{{$t('api_test.request.address')}} :
<pre>{{ request.url }}</pre>
</div>
<div class="ms-div">
{{$t('api_test.scenario.headers')}} :
<pre>{{ request.headers }}</pre>
</div>
<div class="ms-div">
Cookies :
<pre>{{request.cookies}}</pre>
</div>
<div class="ms-div">
Body :
<pre>{{request.body}}</pre>
</div>
</el-tab-pane>
<el-tab-pane v-if="activeName == 'body'" :disabled="true" name="mode" class="pane assertions">
<template v-slot:label>
<ms-dropdown v-if="!isSqlType" :commands="modes" :default-command="mode" @command="modeChange"/>
<ms-dropdown v-if="isSqlType" :commands="sqlModes" :default-command="mode" @command="sqlModeChange"/>
</template>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.definition.request.console')" name="console" class="pane">
<pre>{{response.console}}</pre>
</el-tab-pane>
</el-tabs>
</el-collapse-transition>
</div>
</template>
<script>
import MsAssertionResults from "./AssertionResults";
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
import MsDropdown from "../../../../common/components/MsDropdown";
import {BODY_FORMAT, RequestFactory, Request, SqlRequest} from "../../../definition/model/ApiTestModel";
import MsSqlResultTable from "./SqlResultTable";
import MsAssertionResults from "./AssertionResults";
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
import MsDropdown from "../../../../common/components/MsDropdown";
import {BODY_FORMAT, RequestFactory, Request, SqlRequest} from "../../../definition/model/ApiTestModel";
import MsSqlResultTable from "./SqlResultTable";
export default {
name: "MsResponseText",
export default {
name: "MsResponseText",
components: {
MsSqlResultTable,
MsDropdown,
MsCodeEdit,
MsAssertionResults,
},
props: {
requestType: String,
response: Object
},
data() {
return {
isActive: true,
activeName: "body",
modes: ['text', 'json', 'xml', 'html'],
sqlModes: ['text', 'table'],
mode: BODY_FORMAT.TEXT
}
},
methods: {
active() {
this.isActive = !this.isActive;
components: {
MsSqlResultTable,
MsDropdown,
MsCodeEdit,
MsAssertionResults,
},
modeChange(mode) {
this.mode = mode;
props: {
requestType: String,
request: {},
response: Object
},
sqlModeChange(mode) {
this.mode = mode;
}
},
mounted() {
if (!this.response.headers) {
return;
}
if (this.response.headers.indexOf("Content-Type: application/json") > 0) {
this.mode = BODY_FORMAT.JSON;
}
},
data() {
return {
isActive: true,
activeName: "body",
modes: ['text', 'json', 'xml', 'html'],
sqlModes: ['text', 'table'],
mode: BODY_FORMAT.TEXT
}
},
computed: {
isSqlType() {
return (this.requestType === RequestFactory.TYPES.SQL && this.response.responseCode === '200');
methods: {
active() {
this.isActive = !this.isActive;
},
modeChange(mode) {
this.mode = mode;
},
sqlModeChange(mode) {
this.mode = mode;
}
},
mounted() {
if (!this.response.headers) {
return;
}
if (this.response.headers.indexOf("Content-Type: application/json") > 0) {
this.mode = BODY_FORMAT.JSON;
}
},
computed: {
isSqlType() {
return (this.requestType === RequestFactory.TYPES.SQL && this.response.responseCode === '200');
}
}
}
}
</script>
<style scoped>
@ -134,4 +153,7 @@ export default {
margin: 0;
}
.ms-div {
margin-top: 20px;
}
</style>

View File

@ -5,15 +5,22 @@
<div class="el-step__icon is-text ms-api-col" v-if="request.referenced!=undefined && request.referenced==='Deleted' || request.referenced=='REF' || request.referenced==='Copy'">
<div class="el-step__icon-inner">{{request.index}}</div>
</div>
<div class="el-step__icon is-text ms-api-col-ot-import" v-else-if="request.referenced!=undefined && request.referenced==='OT_IMPORT'">
<div class="el-step__icon-inner">{{request.index}}</div>
</div>
<div class="el-step__icon is-text ms-api-col-create" v-else>
<div class="el-step__icon-inner">{{request.index}}</div>
</div>
<el-button v-if="request.referenced!=undefined && request.referenced==='Deleted' || request.referenced=='REF' || request.referenced==='Copy'" class="ms-left-buttion" size="small">
<el-button v-if="request.referenced!=undefined && request.referenced==='Deleted' || request.referenced=='REF' || request.referenced==='Copy'" class="ms-left-button" size="small">
{{$t('api_test.automation.api_list_import')}}
</el-button>
<el-button v-if="request.referenced==undefined || request.referenced==='Created' " class="ms-create-buttion" size="small">
<el-button v-if="request.referenced!=undefined && request.referenced==='OT_IMPORT'" class="ms-api-col-ot-import-button" size="small">
{{$t('api_test.automation.external_import')}}
</el-button>
<el-button v-if="request.referenced==undefined || request.referenced==='Created' " class="ms-create-button" size="small">
{{$t('api_test.automation.customize_req')}}
</el-button>
@ -37,7 +44,12 @@
<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-input :placeholder="$t('api_test.definition.request.path_all_info')" v-if="request.url" 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>
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-else v-model="request.path" 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>
@ -96,20 +108,10 @@
try {
let urlObject = new URL(this.request.url);
let url = urlObject.protocol + "//" + urlObject.host + "/";
if (url) {
let path = this.request.url.substr(url.length);
if (!path.startsWith('/')) {
path = "/" + path;
}
this.request.path = path;
} else {
this.request.url = this.request.path;
}
} catch (e) {
if (this.request.url) {
this.request.path = this.request.url;
} else {
this.request.url = this.request.path;
this.request.url = undefined;
}
}
}
@ -201,7 +203,7 @@
color: #F56C6C;
}
.ms-left-buttion {
.ms-left-button {
color: #F56C6C;
background-color: #FCF1F1;
margin-right: 20px;
@ -214,6 +216,19 @@
color: #008080;
}
.ms-api-col-ot-import {
background-color: #EEF5FE;
border-color: #409EFF;
margin-right: 10px;
color: #409EFF;
}
.ms-api-col-ot-import-button {
background-color: #EEF5FE;
margin-right: 20px;
color: #409EFF;
}
/deep/ .el-card__body {
padding: 15px;
}
@ -222,7 +237,7 @@
transform: rotate(90deg);
}
.ms-create-buttion {
.ms-create-button {
color: #008080;
background-color: #EBF2F2;
margin-right: 20px;

View File

@ -782,7 +782,7 @@
apiImport(importData) {
if (importData && importData.data) {
importData.data.forEach(item => {
this.setApiParameter(item, "API", "Copy");
this.setApiParameter(item, "API", "OT_IMPORT");
})
this.sort();
this.reload();
@ -945,8 +945,4 @@
font-size: 13px;
}
/deep/ .el-form-item__content {
line-height: 100%;
}
</style>

View File

@ -78,10 +78,10 @@
<!-- 测试-->
<div v-else-if="item.type=== 'TEST'" class="ms-api-div">
<ms-run-test-http-page :currentProtocol="currentProtocol" :api-data="item.api" @saveAsApi="editApi" v-if="currentProtocol==='HTTP'"/>
<ms-run-test-tcp-page :currentProtocol="currentProtocol" :api-data="item.api" @saveAsApi="editApi" v-if="currentProtocol==='TCP'"/>
<ms-run-test-sql-page :currentProtocol="currentProtocol" :api-data="item.api" @saveAsApi="editApi" v-if="currentProtocol==='SQL'"/>
<ms-run-test-dubbo-page :currentProtocol="currentProtocol" :api-data="item.api" @saveAsApi="editApi" v-if="currentProtocol==='DUBBO'"/>
<ms-run-test-http-page :currentProtocol="currentProtocol" :api-data="item.api" @saveAsApi="editApi" @refresh="refresh" v-if="currentProtocol==='HTTP'"/>
<ms-run-test-tcp-page :currentProtocol="currentProtocol" :api-data="item.api" @saveAsApi="editApi" @refresh="refresh" v-if="currentProtocol==='TCP'"/>
<ms-run-test-sql-page :currentProtocol="currentProtocol" :api-data="item.api" @saveAsApi="editApi" @refresh="refresh" v-if="currentProtocol==='SQL'"/>
<ms-run-test-dubbo-page :currentProtocol="currentProtocol" :api-data="item.api" @saveAsApi="editApi" @refresh="refresh" v-if="currentProtocol==='DUBBO'"/>
</div>
</el-tab-pane>
</el-tabs>

View File

@ -172,9 +172,9 @@
}
}
this.apiCaseList = response.data;
// if (this.apiCaseList.length == 0) {
// this.addCase();
// }
if (this.apiCaseList.length == 0 && !this.loaded) {
this.addCase();
}
});
}
},

View File

@ -22,7 +22,7 @@
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request"/>
<ms-basis-parameters :showScript="false" :request="request"/>
</div>
</template>

View File

@ -77,7 +77,7 @@
<!-- 请求参数 -->
<div>
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :request="request" :headers="request.headers" :isShowEnable="isShowEnable"/>
<ms-api-request-form :showScript="false" :request="request" :headers="request.headers" :isShowEnable="isShowEnable"/>
</div>
</el-form>

View File

@ -21,7 +21,7 @@
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request"/>
<ms-basis-parameters :showScript="false" :request="request"/>
</div>
</template>

View File

@ -16,7 +16,7 @@
<el-form-item>
<el-dropdown split-button type="primary" class="ms-api-buttion" @click="handleCommand"
@command="handleCommand" size="small" v-if="testCase===undefined">
@command="handleCommand" size="small" v-if="testCase===undefined && !scenario">
{{$t('commons.test')}}
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="save_as">{{$t('api_test.definition.request.save_as')}}</el-dropdown-item>
@ -76,7 +76,9 @@
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
url: [
{max: 500, required: true, message: this.$t('commons.input_limit', [1, 500]), trigger: 'blur'},
{validator: validateURL, trigger: 'blur'}
/*
{validator: validateURL, trigger: 'blur'}
*/
],
},
debugForm: {method: REQ_METHOD[0].id, environmentId: ""},

View File

@ -77,7 +77,7 @@
</div>
</el-col>
<el-col :span="3" class="ms-left-cell">
<el-col :span="3" class="ms-left-cell" v-if="showScript">
<el-button class="ms-left-buttion" size="small" style="color: #B8741A;background-color: #F9F1EA" @click="addPre">+{{$t('api_test.definition.request.pre_script')}}</el-button>
<br/>
@ -120,6 +120,10 @@
request: {},
basisData: {},
moduleOptions: Array,
showScript: {
type: Boolean,
default: true,
},
isReadOnly: {
type: Boolean,
default: false
@ -172,7 +176,7 @@
this.reload();
},
copyRow(row) {
let obj =JSON.parse(JSON.stringify(row));
let obj = JSON.parse(JSON.stringify(row));
obj.id = getUUID();
this.request.hashTree.push(obj);
this.reload();

View File

@ -57,7 +57,7 @@
</div>
</el-col>
<el-col :span="3" class="ms-left-cell">
<el-col :span="3" class="ms-left-cell" v-if="showScript">
<el-button class="ms-left-buttion" size="small" style="color: #B8741A;background-color: #F9F1EA" @click="addPre">+{{$t('api_test.definition.request.pre_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" style="color: #783887;background-color: #F2ECF3" @click="addPost">+{{$t('api_test.definition.request.post_script')}}</el-button>
@ -105,6 +105,10 @@
type: Boolean,
default: false
},
showScript: {
type: Boolean,
default: true,
}
},
data() {
return {
@ -141,7 +145,7 @@
this.reload();
},
copyRow(row) {
let obj =JSON.parse(JSON.stringify(row));
let obj = JSON.parse(JSON.stringify(row));
obj.id = getUUID();
this.request.hashTree.push(obj);
this.reload();

View File

@ -85,7 +85,7 @@
</div>
</el-col>
<!--操作按钮-->
<el-col :span="3" class="ms-left-cell" v-if="!referenced">
<el-col :span="3" class="ms-left-cell" v-if="!referenced && showScript">
<el-button class="ms-left-buttion" size="small" @click="addPre">+{{$t('api_test.definition.request.pre_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" @click="addPost">+{{$t('api_test.definition.request.post_script')}}</el-button>
@ -131,6 +131,7 @@
},
props: {
request: {},
showScript: Boolean,
headers: {
type: Array,
default() {

View File

@ -1,6 +1,6 @@
<template>
<div class="request-form">
<component :is="component" :is-read-only="isReadOnly" :referenced="referenced" :request="request" :headers="headers" :isShowEnable="isShowEnable"/>
<component :is="component" :showScript="showScript" :is-read-only="isReadOnly" :referenced="referenced" :request="request" :headers="headers" :isShowEnable="isShowEnable"/>
</div>
</template>
@ -17,6 +17,10 @@
type: Boolean,
default: true
},
showScript: {
type: Boolean,
default: true,
},
referenced: {
type: Boolean,
default: false

View File

@ -29,7 +29,7 @@
</el-card>
<!-- 加载用例 -->
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :currentApi="api"
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="refresh" @selectTestCase="selectTestCase" :currentApi="api"
:loaded="loaded" :refreshSign="refreshSign" :createCase="createCase"
ref="caseList"/>
@ -104,6 +104,9 @@
return this.runTest();
}
},
refresh(){
this.$emit('refresh');
},
runTest() {
this.loading = true;
this.api.request.name = this.api.id;

View File

@ -70,7 +70,7 @@
</el-card>
<!-- 加载用例 -->
<ms-api-case-list @selectTestCase="selectTestCase"
<ms-api-case-list @selectTestCase="selectTestCase" @refresh="refresh"
:loaded="loaded"
:refreshSign="refreshSign"
:createCase="createCase"
@ -273,6 +273,9 @@
environmentConfigClose() {
this.getEnvironments();
},
refresh(){
this.$emit('refresh');
},
getResult() {
let url = "/api/definition/report/getReport/" + this.api.id;
this.$get(url, response => {

View File

@ -28,7 +28,7 @@
</el-card>
<!-- 加载用例 -->
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :currentApi="api" :refreshSign="refreshSign"
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="refresh" @selectTestCase="selectTestCase" :currentApi="api" :refreshSign="refreshSign"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
@ -103,6 +103,9 @@
return this.$refs['requestForm'].validate();
}
},
refresh(){
this.$emit('refresh');
},
runTest() {
this.loading = true;
this.api.request.name = this.api.id;

View File

@ -29,7 +29,7 @@
</el-card>
<!-- 加载用例 -->
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :currentApi="api" :refreshSign="refreshSign"
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="refresh" @selectTestCase="selectTestCase" :currentApi="api" :refreshSign="refreshSign"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
<!-- 环境 -->
@ -103,6 +103,9 @@
return this.$refs['requestForm'].validate();
}
},
refresh(){
this.$emit('refresh');
},
runTest() {
this.loading = true;
this.api.request.name = this.api.id;

View File

@ -47,14 +47,14 @@
<el-dialog
:close-on-click-modal="false"
:title="$t('test_resource_pool.create_resource_pool')"
:visible.sync="createVisible" width="70%"
:title="form.id ? $t('test_resource_pool.update_resource_pool') : $t('test_resource_pool.create_resource_pool')"
:visible.sync="dialogVisible" width="70%"
@closed="closeFunc"
:destroy-on-close="true"
v-loading="result.loading"
>
<el-form :model="form" label-position="right" label-width="120px" size="small" :rules="rule"
ref="createTestResourcePoolForm">
ref="testResourcePoolForm">
<el-form-item :label="$t('commons.name')" prop="name">
<el-input v-model="form.name" autocomplete="off"/>
</el-form-item>
@ -75,22 +75,25 @@
<div class="node-line" v-if="form.type === 'K8S'" v-xpack>
<el-row>
<el-col>
<el-form-item prop="masterUrl" label="Master URL">
<el-form-item label="Master URL"
:rules="requiredRules">
<el-input v-model="item.masterUrl" autocomplete="new-password"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item prop="password" label="Token">
<el-form-item label="Token"
:rules="requiredRules">
<el-input v-model="item.token" type="password" show-password autocomplete="new-password"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="1000000000"></el-input-number>
<el-form-item :label="$t('test_resource_pool.max_threads')"
:rules="requiredRules">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="1000000000"/>
</el-form-item>
</el-col>
</el-row>
@ -98,17 +101,19 @@
<div class="node-line" v-if="form.type === 'NODE'">
<el-row>
<el-col :span="8">
<el-form-item prop="ip" label="IP">
<el-form-item label="IP" :rules="requiredRules">
<el-input v-model="item.ip" autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="port" label="Port" style="padding-left: 20px">
<el-form-item label="Port" style="padding-left: 20px"
:rules="requiredRules">
<el-input-number v-model="item.port" :min="1" :max="65535"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
<el-form-item :label="$t('test_resource_pool.max_threads')"
:rules="requiredRules"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="1000000000"></el-input-number>
</el-form-item>
@ -132,100 +137,15 @@
</el-form>
<template v-slot:footer>
<ms-dialog-footer
@cancel="createVisible = false"
@confirm="createTestResourcePool('createTestResourcePoolForm')"/>
</template>
</el-dialog>
<el-dialog
:close-on-click-modal="false"
v-loading="result.loading"
:title="$t('test_resource_pool.update_resource_pool')" :visible.sync="updateVisible" width="70%"
:destroy-on-close="true"
@close="closeFunc">
<el-form :model="form" label-position="right" label-width="120px" size="small" :rules="rule"
ref="updateTestResourcePoolForm">
<el-form-item :label="$t('commons.name')" prop="name">
<el-input v-model="form.name" autocomplete="off"/>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input v-model="form.description" autocomplete="off"/>
</el-form-item>
<el-form-item :label="$t('commons.image')" prop="image">
<el-input v-model="form.image" autocomplete="off"/>
</el-form-item>
<el-form-item :label="$t('test_resource_pool.type')" prop="type">
<el-select v-model="form.type" :placeholder="$t('test_resource_pool.select_pool_type')"
@change="changeResourceType()">
<el-option key="NODE" value="NODE" label="Node">Node</el-option>
<el-option key="K8S" value="K8S" label="Kubernetes" v-xpack>Kubernetes</el-option>
</el-select>
</el-form-item>
<div v-for="(item,index) in infoList " :key="index">
<div class="node-line" v-if="form.type === 'K8S'" v-xpack>
<el-row>
<el-col>
<el-form-item prop="masterUrl" label="Master URL">
<el-input v-model="item.masterUrl" autocomplete="off"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item prop="password" label="Token">
<el-input v-model="item.token" type="password" show-password autocomplete="off"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="1000000000"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="node-line" v-if="form.type === 'NODE'">
<el-row>
<el-col :span="8">
<el-form-item prop="ip" label="IP">
<el-input v-model="item.ip" autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="port" label="Port" style="padding-left: 20px">
<el-input-number v-model="item.port" :min="1" :max="65535"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="1000000000"></el-input-number>
</el-form-item>
</el-col>
<el-col :offset="2" :span="2">
<span class="box">
<el-button @click="addResourceInfo()" type="success" size="mini" circle>
<font-awesome-icon :icon="['fas', 'plus']"/>
</el-button>
</span>
<span class="box">
<el-button @click="removeResourceInfo(index)" type="danger" size="mini" circle>
<font-awesome-icon :icon="['fas', 'minus']"/>
</el-button>
</span>
</el-col>
</el-row>
</div>
</div>
</el-form>
<template v-slot:footer>
v-if="form.id"
@cancel="dialogVisible = false"
@confirm="updateTestResourcePool()"/>
<ms-dialog-footer
@cancel="updateVisible = false"
@confirm="updateTestResourcePool('updateTestResourcePoolForm')"/>
v-else
@cancel="dialogVisible = false"
@confirm="createTestResourcePool()"/>
</template>
</el-dialog>
</div>
</template>
@ -235,7 +155,7 @@ import MsTablePagination from "../../common/pagination/TablePagination";
import MsTableHeader from "../../common/components/MsTableHeader";
import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
import {listenGoBack, removeGoBackListener} from "../../../../common/js/utils";
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
export default {
name: "MsTestResourcePool",
@ -243,9 +163,8 @@ export default {
data() {
return {
result: {},
createVisible: false,
dialogVisible: false,
infoList: [],
updateVisible: false,
queryPath: "testresourcepool/list",
condition: {},
items: [],
@ -253,6 +172,7 @@ export default {
pageSize: 5,
total: 0,
form: {},
requiredRules: [{required: true, message: this.$t('test_resource_pool.fill_the_data'), trigger: 'blur'}],
rule: {
name: [
{required: true, message: this.$t('test_resource_pool.input_pool_name'), trigger: 'blur'},
@ -329,11 +249,11 @@ export default {
this.initTableData();
},
create() {
this.createVisible = true;
this.dialogVisible = true;
listenGoBack(this.closeFunc);
},
edit(row) {
this.updateVisible = true;
this.dialogVisible = true;
this.form = JSON.parse(JSON.stringify(row));
this.convertResources();
listenGoBack(this.closeFunc);
@ -363,8 +283,8 @@ export default {
this.$info(this.$t('commons.delete_cancel'));
});
},
createTestResourcePool(createTestResourcePoolForm) {
this.$refs[createTestResourcePoolForm].validate(valid => {
createTestResourcePool() {
this.$refs.testResourcePoolForm.validate(valid => {
if (valid) {
let vri = this.validateResourceInfo();
if (vri.validate) {
@ -374,7 +294,7 @@ export default {
type: 'success',
message: this.$t('commons.save_success')
},
this.createVisible = false,
this.dialogVisible = false,
this.initTableData());
});
} else {
@ -400,8 +320,8 @@ export default {
});
this.form.resources = resources;
},
updateTestResourcePool(updateTestResourcePoolForm) {
this.$refs[updateTestResourcePoolForm].validate(valid => {
updateTestResourcePool() {
this.$refs.testResourcePoolForm.validate(valid => {
if (valid) {
let vri = this.validateResourceInfo();
if (vri.validate) {
@ -411,7 +331,7 @@ export default {
type: 'success',
message: this.$t('commons.modify_success')
},
this.updateVisible = false,
this.dialogVisible = false,
this.initTableData(),
self.loading = false);
});
@ -426,8 +346,7 @@ export default {
},
closeFunc() {
this.form = {};
this.updateVisible = false;
this.createVisible = false;
this.dialogVisible = false;
removeGoBackListener(this.closeFunc);
},
changeSwitch(row) {

View File

@ -19,6 +19,7 @@
@testCaseDetail="showTestCaseDetail"
@batchMove="batchMove"
@refresh="refresh"
@refreshAll="refreshAll"
@moveToNode="moveToNode"
ref="testCaseList">
</test-case-list>
@ -131,6 +132,10 @@ export default {
this.selectNode = {};
this.refreshTable();
},
refreshAll() {
this.$refs.nodeTree.list();
this.refresh();
},
openRecentTestCaseEditDialog(caseId) {
if (caseId) {
// this.getProjectByCaseId(caseId);

View File

@ -204,7 +204,7 @@
if (res.success) {
this.$success(this.$t('test_track.case.import.success'));
this.dialogVisible = false;
this.$emit("refresh");
this.$emit("refreshAll");
} else {
this.errList = res.errList;
}
@ -223,7 +223,7 @@
if (res.success) {
this.$success(this.$t('test_track.case.import.success'));
this.dialogVisible = false;
this.$emit("refresh");
this.$emit("refreshAll");
} else {
this.xmindErrList = res.errList;
}

View File

@ -25,7 +25,7 @@
</template>
<test-case-import @refresh="refresh" ref="testCaseImport"/>
<test-case-import @refreshAll="refreshAll" ref="testCaseImport"/>
<el-table
border
@ -374,6 +374,10 @@ export default {
this.selectRows.clear();
this.$emit('refresh');
},
refreshAll() {
this.selectRows.clear();
this.$emit('refreshAll');
},
showDetail(row, event, column) {
this.$emit('testCaseDetail', row);
},