初版本保存完成

This commit is contained in:
fit2-zhao 2020-11-06 18:24:11 +08:00
parent 519338e508
commit b8b5d7d1d3
43 changed files with 4758 additions and 745 deletions

View File

@ -0,0 +1,57 @@
package io.metersphere.api.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.delimit.ApiDelimitRequest;
import io.metersphere.api.dto.delimit.ApiDelimitResult;
import io.metersphere.api.dto.delimit.SaveApiDelimitRequest;
import io.metersphere.api.service.ApiDelimitService;
import io.metersphere.base.domain.ApiDelimit;
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 org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping(value = "/api/delimit")
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR)
public class ApiDelimitController {
@Resource
private ApiDelimitService apiDelimitService;
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<ApiDelimitResult>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDelimitRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return PageUtils.setPageInfo(page, apiDelimitService.list(request));
}
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
public void create(@RequestPart("request") SaveApiDelimitRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiDelimitService.create(request, file, bodyFiles);
}
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
public void update(@RequestPart("request") SaveApiDelimitRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiDelimitService.update(request, file, bodyFiles);
}
@GetMapping("/delete/{id}")
public void delete(@PathVariable String id) {
apiDelimitService.delete(id);
}
@GetMapping("/get/{id}")
public ApiDelimit get(@PathVariable String id) {
return apiDelimitService.get(id);
}
}

View File

@ -23,10 +23,10 @@ public class ApiModuleController {
@Resource
private CheckOwnerService checkOwnerService;
@GetMapping("/list/{projectId}")
@GetMapping("/list/{projectId}/{protocol}")
public List<ApiModuleDTO> getNodeByProjectId(@PathVariable String projectId,@PathVariable String protocol) {
checkOwnerService.checkProjectOwner(projectId);
return apiModuleService.getNodeTreeByProjectId(projectId);
return apiModuleService.getNodeTreeByProjectId(projectId,protocol);
}
@PostMapping("/add")

View File

@ -0,0 +1,46 @@
package io.metersphere.api.controller;
import io.metersphere.api.dto.delimit.ApiTestCaseRequest;
import io.metersphere.api.dto.delimit.ApiTestCaseResult;
import io.metersphere.api.dto.delimit.SaveApiTestCaseRequest;
import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.SessionUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping(value = "/api/testcase")
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR)
public class ApiTestCaseController {
@Resource
private ApiTestCaseService apiTestCaseService;
@PostMapping("/list")
public List<ApiTestCaseResult> list(@RequestBody ApiTestCaseRequest request) {
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return apiTestCaseService.list(request);
}
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
public void create(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiTestCaseService.create(request, file, bodyFiles);
}
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
public void update(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiTestCaseService.update(request, file, bodyFiles);
}
@GetMapping("/delete/{id}")
public void delete(@PathVariable String id) {
apiTestCaseService.delete(id);
}
}

View File

@ -0,0 +1,13 @@
package io.metersphere.api.dto.delimit;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ApiComputeResult {
private String apiDelimitId;
private String caseTotal;
private String status;
private String passRate;
}

View File

@ -0,0 +1,27 @@
package io.metersphere.api.dto.delimit;
import io.metersphere.controller.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class ApiDelimitRequest {
private String id;
private String excludeId;
private String projectId;
private String moduleId;
private List<String> moduleIds;
private String name;
private String workspaceId;
private String userId;
private boolean recent = false;
private List<OrderRequest> orders;
private Map<String, List<String>> filters;
private Map<String, Object> combine;
private List<String> ids;
}

View File

@ -0,0 +1,23 @@
package io.metersphere.api.dto.delimit;
import io.metersphere.base.domain.ApiDelimit;
import io.metersphere.base.domain.Schedule;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class ApiDelimitResult extends ApiDelimit {
private String projectName;
private String userName;
private String caseTotal;
private String caseStatus;
private String casePassingRate;
private Schedule schedule;
}

View File

@ -0,0 +1,21 @@
package io.metersphere.api.dto.delimit;
import io.metersphere.controller.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class ApiTestCaseRequest {
private String id;
private String projectId;
private String priority;
private String name;
private String environmentId;
private String workspaceId;
private String apiDelimitId;
private List<OrderRequest> orders;
}

View File

@ -0,0 +1,15 @@
package io.metersphere.api.dto.delimit;
import io.metersphere.base.domain.ApiTestCase;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class ApiTestCaseResult extends ApiTestCase {
private String projectName;
private String createUser;
private String updateUser;
private String execResult;
private boolean active = false;
}

View File

@ -0,0 +1,41 @@
package io.metersphere.api.dto.delimit;
import io.metersphere.api.dto.scenario.request.Request;
import io.metersphere.base.domain.Schedule;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class SaveApiDelimitRequest {
private String id;
private String projectId;
private String name;
private String url;
private String moduleId;
private String status;
private String description;
private String modulePath;
private String path;
private Request request;
private String userId;
private Schedule schedule;
private String triggerMode;
private List<String> bodyUploadIds;
}

View File

@ -0,0 +1,38 @@
package io.metersphere.api.dto.delimit;
import io.metersphere.api.dto.scenario.request.Request;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class SaveApiTestCaseRequest {
private String id;
private String projectId;
private String name;
private String priority;
private String apiDelimitId;
private String description;
private Request request;
private String response;
private String crateUserId;
private String updateUserId;
private Long createTime;
private Long updateTime;
private List<String> bodyUploadIds;
}

View File

@ -0,0 +1,11 @@
package io.metersphere.api.dto.scenario;
import lombok.Data;
@Data
public class AuthConfig {
private String verification;
private String username;
private String password;
}

View File

@ -2,6 +2,7 @@ package io.metersphere.api.dto.scenario.request;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.scenario.AuthConfig;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.KeyValue;
import lombok.Data;
@ -37,4 +38,8 @@ public class HttpRequest extends Request {
private Boolean followRedirects;
@JSONField(ordinal = 17)
private Boolean doMultipartPost;
@JSONField(ordinal = 18)
private List<KeyValue> rest;
@JSONField(ordinal = 19)
private AuthConfig authConfig;
}

View File

@ -0,0 +1,223 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.delimit.ApiComputeResult;
import io.metersphere.api.dto.delimit.ApiDelimitRequest;
import io.metersphere.api.dto.delimit.ApiDelimitResult;
import io.metersphere.api.dto.delimit.SaveApiDelimitRequest;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDelimitMapper;
import io.metersphere.base.mapper.ApiTestFileMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.service.FileService;
import io.metersphere.service.QuotaService;
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 javax.annotation.Resource;
import java.io.*;
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;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiDelimitService {
@Resource
private ApiDelimitMapper apiDelimitMapper;
@Resource
private ApiTestFileMapper apiTestFileMapper;
@Resource
private FileService fileService;
@Resource
private ApiTestCaseService apiTestCaseService;
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
public List<ApiDelimitResult> list(ApiDelimitRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
List<ApiDelimitResult> resList = apiDelimitMapper.list(request);
if (!resList.isEmpty()) {
List<String> ids = resList.stream().map(ApiDelimitResult::getId).collect(Collectors.toList());
List<ApiComputeResult> results = apiDelimitMapper.selectByIds(ids);
Map<String, ApiComputeResult> resultMap = results.stream().collect(Collectors.toMap(ApiComputeResult::getApiDelimitId, Function.identity()));
for (ApiDelimitResult res : resList) {
ApiComputeResult compRes = resultMap.get(res.getId());
if (compRes != null) {
res.setCaseTotal(compRes.getCaseTotal());
res.setCasePassingRate(compRes.getPassRate());
res.setCaseStatus(compRes.getStatus());
} else {
res.setCaseTotal("-");
res.setCasePassingRate("-");
res.setCaseStatus("-");
}
}
}
return resList;
}
public ApiDelimit get(String id) {
return apiDelimitMapper.selectByPrimaryKey(id);
}
public void create(SaveApiDelimitRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
ApiDelimit test = createTest(request, file);
createBodyFiles(test, bodyUploadIds, bodyFiles);
}
private ApiDelimit createTest(SaveApiDelimitRequest request, MultipartFile file) {
if (file == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
}
checkQuota();
request.setBodyUploadIds(null);
ApiDelimit test = createTest(request);
saveFile(test.getId(), file);
return test;
}
private void checkQuota() {
QuotaService quotaService = CommonBeanFactory.getBean(QuotaService.class);
if (quotaService != null) {
quotaService.checkAPITestQuota();
}
}
public void update(SaveApiDelimitRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
if (file == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
}
deleteFileByTestId(request.getId());
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
request.setBodyUploadIds(null);
ApiDelimit test = updateTest(request);
createBodyFiles(test, bodyUploadIds, bodyFiles);
saveFile(test.getId(), file);
}
private void createBodyFiles(ApiDelimit test, List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (bodyUploadIds.size() > 0) {
String dir = BODY_FILE_DIR + "/" + test.getId();
File testDir = new File(dir);
if (!testDir.exists()) {
testDir.mkdirs();
}
for (int i = 0; i < bodyUploadIds.size(); i++) {
MultipartFile item = bodyFiles.get(i);
File file = new File(testDir + "/" + 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 delete(String apiId) {
apiTestCaseService.checkIsRelateTest(apiId);
deleteFileByTestId(apiId);
//apiReportService.deleteByTestId(apiId);
apiDelimitMapper.deleteByPrimaryKey(apiId);
deleteBodyFiles(apiId);
}
public void deleteBodyFiles(String apiId) {
File file = new File(BODY_FILE_DIR + "/" + apiId);
FileUtil.deleteContents(file);
if (file.exists()) {
file.delete();
}
}
private void checkNameExist(SaveApiDelimitRequest request) {
ApiDelimitExample example = new ApiDelimitExample();
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
if (apiDelimitMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("load_test_already_exists"));
}
}
private ApiDelimit updateTest(SaveApiDelimitRequest request) {
checkNameExist(request);
final ApiDelimit test = new ApiDelimit();
test.setId(request.getId());
test.setName(request.getName());
test.setProjectId(request.getProjectId());
test.setRequest(JSONObject.toJSONString(request.getRequest()));
test.setUpdateTime(System.currentTimeMillis());
test.setStatus(request.getStatus());
test.setModulePath(request.getModulePath());
test.setModuleId(request.getModuleId());
test.setPath(request.getPath());
test.setUrl(request.getUrl());
test.setDescription(request.getDescription());
test.setUserId(request.getUserId());
apiDelimitMapper.updateByPrimaryKeySelective(test);
return test;
}
private ApiDelimit createTest(SaveApiDelimitRequest request) {
checkNameExist(request);
final ApiDelimit test = new ApiDelimit();
test.setId(request.getId());
test.setName(request.getName());
test.setUrl(request.getUrl());
test.setPath(request.getPath());
test.setModuleId(request.getModuleId());
test.setProjectId(request.getProjectId());
test.setRequest(JSONObject.toJSONString(request.getRequest()));
test.setCreateTime(System.currentTimeMillis());
test.setUpdateTime(System.currentTimeMillis());
test.setStatus(APITestStatus.Underway.name());
test.setModulePath(request.getModulePath());
if (request.getUserId() == null) {
test.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
} else {
test.setUserId(request.getUserId());
}
test.setDescription(request.getDescription());
apiDelimitMapper.insert(test);
return test;
}
private void saveFile(String apiId, MultipartFile file) {
final FileMetadata fileMetadata = fileService.saveFile(file);
ApiTestFile apiTestFile = new ApiTestFile();
apiTestFile.setTestId(apiId);
apiTestFile.setFileId(fileMetadata.getId());
apiTestFileMapper.insert(apiTestFile);
}
private void deleteFileByTestId(String apiId) {
ApiTestFileExample ApiTestFileExample = new ApiTestFileExample();
ApiTestFileExample.createCriteria().andTestIdEqualTo(apiId);
final List<ApiTestFile> ApiTestFiles = apiTestFileMapper.selectByExample(ApiTestFileExample);
apiTestFileMapper.deleteByExample(ApiTestFileExample);
if (!CollectionUtils.isEmpty(ApiTestFiles)) {
final List<String> fileIds = ApiTestFiles.stream().map(ApiTestFile::getFileId).collect(Collectors.toList());
fileService.deleteFileByIds(fileIds);
}
}
}

View File

@ -1,20 +1,19 @@
package io.metersphere.api.service;
import io.metersphere.api.dto.delimit.ApiDelimitRequest;
import io.metersphere.api.dto.delimit.ApiDelimitResult;
import io.metersphere.api.dto.delimit.ApiModuleDTO;
import io.metersphere.api.dto.delimit.DragModuleRequest;
import io.metersphere.base.domain.ApiDelimitExample;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.base.domain.ApiModuleExample;
import io.metersphere.base.domain.TestCaseExample;
import io.metersphere.base.mapper.ApiDelimitMapper;
import io.metersphere.base.mapper.ApiModuleMapper;
import io.metersphere.base.mapper.TestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.track.dto.TestCaseDTO;
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
@ -33,15 +32,16 @@ public class ApiModuleService {
@Resource
ApiModuleMapper apiModuleMapper;
@Resource
ExtTestCaseMapper extTestCaseMapper;
private ApiDelimitMapper apiDelimitMapper;
@Resource
SqlSessionFactory sqlSessionFactory;
public List<ApiModuleDTO> getNodeTreeByProjectId(String projectId) {
ApiModuleExample testCaseNodeExample = new ApiModuleExample();
testCaseNodeExample.createCriteria().andProjectIdEqualTo(projectId);
testCaseNodeExample.setOrderByClause("create_time asc");
List<ApiModule> nodes = apiModuleMapper.selectByExample(testCaseNodeExample);
public List<ApiModuleDTO> getNodeTreeByProjectId(String projectId, String protocol) {
ApiModuleExample apiDelimitNodeExample = new ApiModuleExample();
apiDelimitNodeExample.createCriteria().andProjectIdEqualTo(projectId);
apiDelimitNodeExample.createCriteria().andProtocolEqualTo(protocol);
apiDelimitNodeExample.setOrderByClause("create_time asc");
List<ApiModule> nodes = apiModuleMapper.selectByExample(apiDelimitNodeExample);
return getNodeTrees(nodes);
}
@ -107,10 +107,10 @@ public class ApiModuleService {
throw new RuntimeException(Translator.get("test_case_node_level_tip")
+ TestCaseConstants.MAX_NODE_DEPTH + Translator.get("test_case_node_level"));
}
checkTestCaseNodeExist(node);
checkApiModuleExist(node);
}
private void checkTestCaseNodeExist(ApiModule node) {
private void checkApiModuleExist(ApiModule node) {
if (node.getName() != null) {
ApiModuleExample example = new ApiModuleExample();
ApiModuleExample.Criteria criteria = example.createCriteria();
@ -130,104 +130,107 @@ public class ApiModuleService {
}
}
private List<TestCaseDTO> QueryTestCaseByNodeIds(List<String> nodeIds) {
QueryTestCaseRequest testCaseRequest = new QueryTestCaseRequest();
testCaseRequest.setNodeIds(nodeIds);
return extTestCaseMapper.list(testCaseRequest);
private List<ApiDelimitResult> queryByModuleIds(List<String> nodeIds) {
ApiDelimitRequest apiDelimitRequest = new ApiDelimitRequest();
apiDelimitRequest.setModuleIds(nodeIds);
return apiDelimitMapper.list(apiDelimitRequest);
}
public int editNode(DragModuleRequest request) {
request.setUpdateTime(System.currentTimeMillis());
checkTestCaseNodeExist(request);
List<TestCaseDTO> apiModule = QueryTestCaseByNodeIds(request.getNodeIds());
checkApiModuleExist(request);
List<ApiDelimitResult> apiModule = queryByModuleIds(request.getNodeIds());
apiModule.forEach(testCase -> {
StringBuilder path = new StringBuilder(testCase.getNodePath());
apiModule.forEach(apiDelimit -> {
StringBuilder path = new StringBuilder(apiDelimit.getModulePath());
List<String> pathLists = Arrays.asList(path.toString().split("/"));
pathLists.set(request.getLevel(), request.getName());
path.delete(0, path.length());
for (int i = 1; i < pathLists.size(); i++) {
path = path.append("/").append(pathLists.get(i));
}
testCase.setNodePath(path.toString());
apiDelimit.setModulePath(path.toString());
});
batchUpdateTestCase(apiModule);
batchUpdateApiDelimit(apiModule);
return apiModuleMapper.updateByPrimaryKeySelective(request);
}
public int deleteNode(List<String> nodeIds) {
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andNodeIdIn(nodeIds);
ApiDelimitExample apiDelimitExample = new ApiDelimitExample();
apiDelimitExample.createCriteria().andModuleIdIn(nodeIds);
apiDelimitMapper.deleteByExample(apiDelimitExample);
ApiModuleExample testCaseNodeExample = new ApiModuleExample();
testCaseNodeExample.createCriteria().andIdIn(nodeIds);
return apiModuleMapper.deleteByExample(testCaseNodeExample);
ApiModuleExample apiDelimitNodeExample = new ApiModuleExample();
apiDelimitNodeExample.createCriteria().andIdIn(nodeIds);
return apiModuleMapper.deleteByExample(apiDelimitNodeExample);
}
private void batchUpdateTestCase(List<TestCaseDTO> apiModule) {
private void batchUpdateApiDelimit(List<ApiDelimitResult> apiModule) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestCaseMapper testCaseMapper = sqlSession.getMapper(TestCaseMapper.class);
ApiDelimitMapper apiDelimitMapper = sqlSession.getMapper(ApiDelimitMapper.class);
apiModule.forEach((value) -> {
testCaseMapper.updateByPrimaryKey(value);
apiDelimitMapper.updateByPrimaryKey(value);
});
sqlSession.flushStatements();
}
public void dragNode(DragModuleRequest request) {
checkTestCaseNodeExist(request);
checkApiModuleExist(request);
List<String> nodeIds = request.getNodeIds();
List<TestCaseDTO> apiModule = QueryTestCaseByNodeIds(nodeIds);
List<ApiDelimitResult> apiModule = queryByModuleIds(nodeIds);
ApiModuleDTO nodeTree = request.getNodeTree();
List<ApiModule> updateNodes = new ArrayList<>();
buildUpdateTestCase(nodeTree, apiModule, updateNodes, "/", "0", 1);
buildUpdateDelimit(nodeTree, apiModule, updateNodes, "/", "0", nodeTree.getLevel());
updateNodes = updateNodes.stream()
.filter(item -> nodeIds.contains(item.getId()))
.collect(Collectors.toList());
batchUpdateTestCaseNode(updateNodes);
batchUpdateModule(updateNodes);
batchUpdateTestCase(apiModule);
batchUpdateApiDelimit(apiModule);
}
private void buildUpdateTestCase(ApiModuleDTO rootNode, List<TestCaseDTO> apiModule,
List<ApiModule> updateNodes, String rootPath, String pId, int level) {
private void buildUpdateDelimit(ApiModuleDTO rootNode, List<ApiDelimitResult> apiDelimits,
List<ApiModule> updateNodes, String rootPath, String pId, int level) {
rootPath = rootPath + rootNode.getName();
if (level > 8) {
MSException.throwException(Translator.get("node_deep_limit"));
}
if (rootNode.getId().equals("rootID")) {
rootPath = "";
}
ApiModule apiDelimitNode = new ApiModule();
apiDelimitNode.setId(rootNode.getId());
apiDelimitNode.setLevel(level);
apiDelimitNode.setParentId(pId);
updateNodes.add(apiDelimitNode);
ApiModule testCaseNode = new ApiModule();
testCaseNode.setId(rootNode.getId());
testCaseNode.setLevel(level);
testCaseNode.setParentId(pId);
updateNodes.add(testCaseNode);
for (TestCaseDTO item : apiModule) {
if (StringUtils.equals(item.getNodeId(), rootNode.getId())) {
item.setNodePath(rootPath);
for (ApiDelimitResult item : apiDelimits) {
if (StringUtils.equals(item.getModuleId(), rootNode.getId())) {
item.setModulePath(rootPath);
}
}
List<ApiModuleDTO> children = rootNode.getChildren();
if (children != null && children.size() > 0) {
for (int i = 0; i < children.size(); i++) {
buildUpdateTestCase(children.get(i), apiModule, updateNodes, rootPath + '/', rootNode.getId(), level + 1);
buildUpdateDelimit(children.get(i), apiDelimits, updateNodes, rootPath + '/', rootNode.getId(), level + 1);
}
}
}
private void batchUpdateTestCaseNode(List<ApiModule> updateNodes) {
private void batchUpdateModule(List<ApiModule> updateNodes) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiModuleMapper apiModuleMapper = sqlSession.getMapper(ApiModuleMapper.class);
updateNodes.forEach((value) -> {

View File

@ -0,0 +1,208 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.delimit.ApiTestCaseRequest;
import io.metersphere.api.dto.delimit.ApiTestCaseResult;
import io.metersphere.api.dto.delimit.SaveApiTestCaseRequest;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.base.mapper.ApiTestFileMapper;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.service.FileService;
import io.metersphere.service.QuotaService;
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 javax.annotation.Resource;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiTestCaseService {
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private ApiTestFileMapper apiTestFileMapper;
@Resource
private FileService fileService;
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
public List<ApiTestCaseResult> list(ApiTestCaseRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
return apiTestCaseMapper.list(request);
}
public ApiTestCase get(String id) {
return apiTestCaseMapper.selectByPrimaryKey(id);
}
public void create(SaveApiTestCaseRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
ApiTestCase test = createTest(request, file);
createBodyFiles(test, bodyUploadIds, bodyFiles);
}
private ApiTestCase createTest(SaveApiTestCaseRequest request, MultipartFile file) {
if (file == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
}
checkQuota();
request.setBodyUploadIds(null);
ApiTestCase test = createTest(request);
saveFile(test.getId(), file);
return test;
}
private void checkQuota() {
QuotaService quotaService = CommonBeanFactory.getBean(QuotaService.class);
if (quotaService != null) {
quotaService.checkAPITestQuota();
}
}
public void update(SaveApiTestCaseRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
if (file == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
}
deleteFileByTestId(request.getId());
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
request.setBodyUploadIds(null);
ApiTestCase test = updateTest(request);
createBodyFiles(test, bodyUploadIds, bodyFiles);
saveFile(test.getId(), file);
}
private void createBodyFiles(ApiTestCase test, List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (bodyUploadIds.size() > 0) {
String dir = BODY_FILE_DIR + "/" + test.getId();
File testDir = new File(dir);
if (!testDir.exists()) {
testDir.mkdirs();
}
for (int i = 0; i < bodyUploadIds.size(); i++) {
MultipartFile item = bodyFiles.get(i);
File file = new File(testDir + "/" + 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 delete(String testId) {
deleteFileByTestId(testId);
//apiReportService.deleteByTestId(testId);
apiTestCaseMapper.deleteByPrimaryKey(testId);
deleteBodyFiles(testId);
}
/**
* 是否已经创建了测试用例
*/
public void checkIsRelateTest(String apiId) {
ApiTestCaseExample testCaseExample = new ApiTestCaseExample();
testCaseExample.createCriteria().andApiDelimitIdEqualTo(apiId);
List<ApiTestCase> testCases = apiTestCaseMapper.selectByExample(testCaseExample);
StringBuilder caseName = new StringBuilder();
if (testCases.size() > 0) {
for (ApiTestCase testCase : testCases) {
caseName = caseName.append(testCase.getName()).append(",");
}
String str = caseName.toString().substring(0, caseName.length() - 1);
MSException.throwException(Translator.get("related_case_del_fail_prefix") + " " + str + " " + Translator.get("related_case_del_fail_suffix"));
}
}
public void deleteBodyFiles(String testId) {
File file = new File(BODY_FILE_DIR + "/" + testId);
FileUtil.deleteContents(file);
if (file.exists()) {
file.delete();
}
}
private void checkNameExist(SaveApiTestCaseRequest request) {
ApiTestCaseExample example = new ApiTestCaseExample();
example.createCriteria().andNameEqualTo(request.getName()).andApiDelimitIdEqualTo(request.getApiDelimitId()).andIdNotEqualTo(request.getId());
if (apiTestCaseMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("load_test_already_exists"));
}
}
private ApiTestCase updateTest(SaveApiTestCaseRequest request) {
checkNameExist(request);
final ApiTestCase test = new ApiTestCase();
test.setId(request.getId());
test.setName(request.getName());
test.setApiDelimitId(request.getApiDelimitId());
test.setUpdateUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
test.setProjectId(request.getProjectId());
test.setRequest(JSONObject.toJSONString(request.getRequest()));
test.setResponse(JSONObject.toJSONString(request.getResponse()));
test.setPriority(request.getPriority());
test.setUpdateTime(System.currentTimeMillis());
test.setDescription(request.getDescription());
apiTestCaseMapper.updateByPrimaryKeySelective(test);
return test;
}
private ApiTestCase createTest(SaveApiTestCaseRequest request) {
request.setId(UUID.randomUUID().toString());
checkNameExist(request);
final ApiTestCase test = new ApiTestCase();
test.setId(request.getId());
test.setName(request.getName());
test.setApiDelimitId(request.getApiDelimitId());
test.setCreateUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
test.setUpdateUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
test.setProjectId(request.getProjectId());
test.setRequest(JSONObject.toJSONString(request.getRequest()));
test.setResponse(JSONObject.toJSONString(request.getResponse()));
test.setCreateTime(System.currentTimeMillis());
test.setPriority(request.getPriority());
test.setUpdateTime(System.currentTimeMillis());
test.setDescription(request.getDescription());
apiTestCaseMapper.insert(test);
return test;
}
private void saveFile(String testId, MultipartFile file) {
final FileMetadata fileMetadata = fileService.saveFile(file);
ApiTestFile apiTestFile = new ApiTestFile();
apiTestFile.setTestId(testId);
apiTestFile.setFileId(fileMetadata.getId());
apiTestFileMapper.insert(apiTestFile);
}
private void deleteFileByTestId(String testId) {
ApiTestFileExample ApiTestFileExample = new ApiTestFileExample();
ApiTestFileExample.createCriteria().andTestIdEqualTo(testId);
final List<ApiTestFile> ApiTestFiles = apiTestFileMapper.selectByExample(ApiTestFileExample);
apiTestFileMapper.deleteByExample(ApiTestFileExample);
if (!CollectionUtils.isEmpty(ApiTestFiles)) {
final List<String> fileIds = ApiTestFiles.stream().map(ApiTestFile::getFileId).collect(Collectors.toList());
fileService.deleteFileByIds(fileIds);
}
}
}

View File

@ -0,0 +1,36 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class ApiDelimit implements Serializable {
private String id;
private String projectId;
private String name;
private String path;
private String url;
private String description;
private String status;
private String userId;
private String moduleId;
private String modulePath;
private Long createTime;
private Long updateTime;
private String request;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,745 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class ApiDelimitExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public ApiDelimitExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andModuleIdIn(List<String> values) {
addCriterion("module_id in", values, "module_id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andProjectIdIsNull() {
addCriterion("project_id is null");
return (Criteria) this;
}
public Criteria andProjectIdIsNotNull() {
addCriterion("project_id is not null");
return (Criteria) this;
}
public Criteria andProjectIdEqualTo(String value) {
addCriterion("project_id =", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("project_id <>", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThan(String value) {
addCriterion("project_id >", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("project_id >=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThan(String value) {
addCriterion("project_id <", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("project_id <=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLike(String value) {
addCriterion("project_id like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotLike(String value) {
addCriterion("project_id not like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdIn(List<String> values) {
addCriterion("project_id in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("project_id not in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andNameIsNull() {
addCriterion("name is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("name is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("name =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("name <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("name >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("name >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("name <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("name <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("name like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("name not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("name in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("name not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("name between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("name not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andDescriptionIsNull() {
addCriterion("description is null");
return (Criteria) this;
}
public Criteria andDescriptionIsNotNull() {
addCriterion("description is not null");
return (Criteria) this;
}
public Criteria andDescriptionEqualTo(String value) {
addCriterion("description =", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotEqualTo(String value) {
addCriterion("description <>", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionGreaterThan(String value) {
addCriterion("description >", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionGreaterThanOrEqualTo(String value) {
addCriterion("description >=", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLessThan(String value) {
addCriterion("description <", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLessThanOrEqualTo(String value) {
addCriterion("description <=", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLike(String value) {
addCriterion("description like", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotLike(String value) {
addCriterion("description not like", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionIn(List<String> values) {
addCriterion("description in", values, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotIn(List<String> values) {
addCriterion("description not in", values, "description");
return (Criteria) this;
}
public Criteria andDescriptionBetween(String value1, String value2) {
addCriterion("description between", value1, value2, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotBetween(String value1, String value2) {
addCriterion("description not between", value1, value2, "description");
return (Criteria) this;
}
public Criteria andStatusIsNull() {
addCriterion("status is null");
return (Criteria) this;
}
public Criteria andStatusIsNotNull() {
addCriterion("status is not null");
return (Criteria) this;
}
public Criteria andStatusEqualTo(String value) {
addCriterion("status =", value, "status");
return (Criteria) this;
}
public Criteria andStatusNotEqualTo(String value) {
addCriterion("status <>", value, "status");
return (Criteria) this;
}
public Criteria andStatusGreaterThan(String value) {
addCriterion("status >", value, "status");
return (Criteria) this;
}
public Criteria andStatusGreaterThanOrEqualTo(String value) {
addCriterion("status >=", value, "status");
return (Criteria) this;
}
public Criteria andStatusLessThan(String value) {
addCriterion("status <", value, "status");
return (Criteria) this;
}
public Criteria andStatusLessThanOrEqualTo(String value) {
addCriterion("status <=", value, "status");
return (Criteria) this;
}
public Criteria andStatusLike(String value) {
addCriterion("status like", value, "status");
return (Criteria) this;
}
public Criteria andStatusNotLike(String value) {
addCriterion("status not like", value, "status");
return (Criteria) this;
}
public Criteria andStatusIn(List<String> values) {
addCriterion("status in", values, "status");
return (Criteria) this;
}
public Criteria andStatusNotIn(List<String> values) {
addCriterion("status not in", values, "status");
return (Criteria) this;
}
public Criteria andStatusBetween(String value1, String value2) {
addCriterion("status between", value1, value2, "status");
return (Criteria) this;
}
public Criteria andStatusNotBetween(String value1, String value2) {
addCriterion("status not between", value1, value2, "status");
return (Criteria) this;
}
public Criteria andUserIdIsNull() {
addCriterion("user_id is null");
return (Criteria) this;
}
public Criteria andUserIdIsNotNull() {
addCriterion("user_id is not null");
return (Criteria) this;
}
public Criteria andUserIdEqualTo(String value) {
addCriterion("user_id =", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotEqualTo(String value) {
addCriterion("user_id <>", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThan(String value) {
addCriterion("user_id >", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThanOrEqualTo(String value) {
addCriterion("user_id >=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThan(String value) {
addCriterion("user_id <", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThanOrEqualTo(String value) {
addCriterion("user_id <=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLike(String value) {
addCriterion("user_id like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotLike(String value) {
addCriterion("user_id not like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdIn(List<String> values) {
addCriterion("user_id in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotIn(List<String> values) {
addCriterion("user_id not in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdBetween(String value1, String value2) {
addCriterion("user_id between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotBetween(String value1, String value2) {
addCriterion("user_id not between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;
}
public Criteria andCreateTimeIsNotNull() {
addCriterion("create_time is not null");
return (Criteria) this;
}
public Criteria andCreateTimeEqualTo(Long value) {
addCriterion("create_time =", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotEqualTo(Long value) {
addCriterion("create_time <>", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThan(Long value) {
addCriterion("create_time >", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("create_time >=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThan(Long value) {
addCriterion("create_time <", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThanOrEqualTo(Long value) {
addCriterion("create_time <=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeIn(List<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> values) {
addCriterion("create_time not in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeBetween(Long value1, Long value2) {
addCriterion("create_time between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotBetween(Long value1, Long value2) {
addCriterion("create_time not between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(Long value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(Long value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(Long value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(Long value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(Long value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<Long> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<Long> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(Long value1, Long value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(Long value1, Long value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -189,6 +189,12 @@ public class ApiModuleExample {
return (Criteria) this;
}
public Criteria andProtocolEqualTo(String value) {
addCriterion("protocol =", value, "protocol");
return (Criteria) this;
}
public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("project_id <>", value, "projectId");
return (Criteria) this;

View File

@ -0,0 +1,34 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class ApiTestCase implements Serializable {
private String id;
private String projectId;
private String name;
private String priority;
private String apiDelimitId;
private String description;
private String request;
private String response;
private String createUserId;
private String updateUserId;
private Long createTime;
private Long updateTime;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,751 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class ApiTestCaseExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public ApiTestCaseExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andModuleIdIn(List<String> values) {
addCriterion("module_id in", values, "module_id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andProjectIdIsNull() {
addCriterion("project_id is null");
return (Criteria) this;
}
public Criteria andProjectIdIsNotNull() {
addCriterion("project_id is not null");
return (Criteria) this;
}
public Criteria andProjectIdEqualTo(String value) {
addCriterion("project_id =", value, "projectId");
return (Criteria) this;
}
public Criteria andApiDelimitIdEqualTo(String value) {
addCriterion("api_delimit_id =", value, "api_delimit_id");
return (Criteria) this;
}
public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("project_id <>", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThan(String value) {
addCriterion("project_id >", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("project_id >=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThan(String value) {
addCriterion("project_id <", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("project_id <=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLike(String value) {
addCriterion("project_id like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotLike(String value) {
addCriterion("project_id not like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdIn(List<String> values) {
addCriterion("project_id in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("project_id not in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andNameIsNull() {
addCriterion("name is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("name is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("name =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("name <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("name >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("name >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("name <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("name <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("name like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("name not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("name in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("name not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("name between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("name not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andDescriptionIsNull() {
addCriterion("description is null");
return (Criteria) this;
}
public Criteria andDescriptionIsNotNull() {
addCriterion("description is not null");
return (Criteria) this;
}
public Criteria andDescriptionEqualTo(String value) {
addCriterion("description =", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotEqualTo(String value) {
addCriterion("description <>", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionGreaterThan(String value) {
addCriterion("description >", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionGreaterThanOrEqualTo(String value) {
addCriterion("description >=", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLessThan(String value) {
addCriterion("description <", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLessThanOrEqualTo(String value) {
addCriterion("description <=", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLike(String value) {
addCriterion("description like", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotLike(String value) {
addCriterion("description not like", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionIn(List<String> values) {
addCriterion("description in", values, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotIn(List<String> values) {
addCriterion("description not in", values, "description");
return (Criteria) this;
}
public Criteria andDescriptionBetween(String value1, String value2) {
addCriterion("description between", value1, value2, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotBetween(String value1, String value2) {
addCriterion("description not between", value1, value2, "description");
return (Criteria) this;
}
public Criteria andStatusIsNull() {
addCriterion("status is null");
return (Criteria) this;
}
public Criteria andStatusIsNotNull() {
addCriterion("status is not null");
return (Criteria) this;
}
public Criteria andStatusEqualTo(String value) {
addCriterion("status =", value, "status");
return (Criteria) this;
}
public Criteria andStatusNotEqualTo(String value) {
addCriterion("status <>", value, "status");
return (Criteria) this;
}
public Criteria andStatusGreaterThan(String value) {
addCriterion("status >", value, "status");
return (Criteria) this;
}
public Criteria andStatusGreaterThanOrEqualTo(String value) {
addCriterion("status >=", value, "status");
return (Criteria) this;
}
public Criteria andStatusLessThan(String value) {
addCriterion("status <", value, "status");
return (Criteria) this;
}
public Criteria andStatusLessThanOrEqualTo(String value) {
addCriterion("status <=", value, "status");
return (Criteria) this;
}
public Criteria andStatusLike(String value) {
addCriterion("status like", value, "status");
return (Criteria) this;
}
public Criteria andStatusNotLike(String value) {
addCriterion("status not like", value, "status");
return (Criteria) this;
}
public Criteria andStatusIn(List<String> values) {
addCriterion("status in", values, "status");
return (Criteria) this;
}
public Criteria andStatusNotIn(List<String> values) {
addCriterion("status not in", values, "status");
return (Criteria) this;
}
public Criteria andStatusBetween(String value1, String value2) {
addCriterion("status between", value1, value2, "status");
return (Criteria) this;
}
public Criteria andStatusNotBetween(String value1, String value2) {
addCriterion("status not between", value1, value2, "status");
return (Criteria) this;
}
public Criteria andUserIdIsNull() {
addCriterion("user_id is null");
return (Criteria) this;
}
public Criteria andUserIdIsNotNull() {
addCriterion("user_id is not null");
return (Criteria) this;
}
public Criteria andUserIdEqualTo(String value) {
addCriterion("user_id =", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotEqualTo(String value) {
addCriterion("user_id <>", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThan(String value) {
addCriterion("user_id >", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThanOrEqualTo(String value) {
addCriterion("user_id >=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThan(String value) {
addCriterion("user_id <", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThanOrEqualTo(String value) {
addCriterion("user_id <=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLike(String value) {
addCriterion("user_id like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotLike(String value) {
addCriterion("user_id not like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdIn(List<String> values) {
addCriterion("user_id in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotIn(List<String> values) {
addCriterion("user_id not in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdBetween(String value1, String value2) {
addCriterion("user_id between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotBetween(String value1, String value2) {
addCriterion("user_id not between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;
}
public Criteria andCreateTimeIsNotNull() {
addCriterion("create_time is not null");
return (Criteria) this;
}
public Criteria andCreateTimeEqualTo(Long value) {
addCriterion("create_time =", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotEqualTo(Long value) {
addCriterion("create_time <>", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThan(Long value) {
addCriterion("create_time >", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("create_time >=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThan(Long value) {
addCriterion("create_time <", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThanOrEqualTo(Long value) {
addCriterion("create_time <=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeIn(List<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> values) {
addCriterion("create_time not in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeBetween(Long value1, Long value2) {
addCriterion("create_time between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotBetween(Long value1, Long value2) {
addCriterion("create_time not between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(Long value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(Long value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(Long value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(Long value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(Long value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<Long> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<Long> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(Long value1, Long value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(Long value1, Long value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -0,0 +1,45 @@
package io.metersphere.base.mapper;
import io.metersphere.api.dto.delimit.ApiComputeResult;
import io.metersphere.api.dto.delimit.ApiDelimitRequest;
import io.metersphere.api.dto.delimit.ApiDelimitResult;
import io.metersphere.base.domain.ApiDelimit;
import io.metersphere.base.domain.ApiDelimitExample;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ApiDelimitMapper {
List<ApiDelimitResult> list(@Param("request") ApiDelimitRequest request);
List<ApiComputeResult> selectByIds(@Param("ids") List<String> ids);
long countByExample(ApiDelimitExample example);
int deleteByExample(ApiDelimitExample example);
int deleteByPrimaryKey(String id);
int insert(ApiDelimit record);
int insertSelective(ApiDelimit record);
List<ApiDelimit> selectByExampleWithBLOBs(ApiDelimitExample example);
List<ApiDelimit> selectByExample(ApiDelimitExample example);
ApiDelimit selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") ApiDelimit record, @Param("example") ApiDelimitExample example);
int updateByExampleWithBLOBs(@Param("record") ApiDelimit record, @Param("example") ApiDelimitExample example);
int updateByExample(@Param("record") ApiDelimit record, @Param("example") ApiDelimitExample example);
int updateByPrimaryKeySelective(ApiDelimit record);
int updateByPrimaryKeyWithBLOBs(ApiDelimit record);
int updateByPrimaryKey(ApiDelimit record);
}

View File

@ -0,0 +1,557 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.ApiDelimitMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiDelimit">
<id column="id" jdbcType="VARCHAR" property="id"/>
<result column="project_id" jdbcType="VARCHAR" property="projectId"/>
<result column="module_id" jdbcType="VARCHAR" property="moduleId"/>
<result column="module_path" jdbcType="VARCHAR" property="modulePath"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="url" jdbcType="VARCHAR" property="url"/>
<result column="path" jdbcType="VARCHAR" property="path"/>
<result column="description" jdbcType="VARCHAR" property="description"/>
<result column="status" jdbcType="VARCHAR" property="status"/>
<result column="user_id" jdbcType="VARCHAR" property="userId"/>
<result column="create_time" jdbcType="BIGINT" property="createTime"/>
<result column="update_time" jdbcType="BIGINT" property="updateTime"/>
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiDelimit">
<result column="request" jdbcType="LONGVARCHAR" property="request"/>
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="("
separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="("
separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, project_id, name,module_id,module_path,url ,path ,description, status, user_id, create_time, update_time
</sql>
<sql id="Blob_Column_List">
request
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.ApiDelimitExample"
resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List"/>
,
<include refid="Blob_Column_List"/>
from api_delimit
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByIds" resultType="io.metersphere.api.dto.delimit.ApiComputeResult">
select t1.api_delimit_id apiDelimitId,count(t1.id) caseTotal,
case t2.status
when 'success' then '通过'
when 'error' then '未通过'
ELSE '未执行' end as status ,
CONCAT(FORMAT(SUM(IF(t2.`status` = 'success', 1, 0))/ COUNT(t1.id)*100, 2), '%') passRate
from api_test_case t1 left join api_delimit_exec_result t2 on t1.id = t2.resource_id
group by t1.api_delimit_id having t1.api_delimit_id in
<foreach collection="ids" item="v" separator="," open="(" close=")">
#{v}
</foreach>
order by t2.end_time desc;
</select>
<sql id="combine">
<if test='${condition}.name != null and (${name} == null or ${name} == "")'>
and api_delimit.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.updateTime != null">
and api_delimit.update_time
<include refid="condition">
<property name="object" value="${condition}.updateTime"/>
</include>
</if>
<if test="${condition}.projectName != null">
and project.name
<include refid="condition">
<property name="object" value="${condition}.projectName"/>
</include>
</if>
<if test="${condition}.createTime != null">
and api_delimit.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.status != null">
and api_delimit.status
<include refid="condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test="${condition}.creator != null">
and api_delimit.user_id
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
</sql>
<sql id="condition">
<choose>
<when test='${object}.operator == "like"'>
like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "not like"'>
not like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "in"'>
in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "not in"'>
not in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "between"'>
between #{${object}.value[0]} and #{${object}.value[1]}
</when>
<when test='${object}.operator == "gt"'>
&gt; #{${object}.value}
</when>
<when test='${object}.operator == "lt"'>
&lt; #{${object}.value}
</when>
<when test='${object}.operator == "ge"'>
&gt;= #{${object}.value}
</when>
<when test='${object}.operator == "le"'>
&lt;= #{${object}.value}
</when>
<when test='${object}.operator == "current user"'>
= '${@io.metersphere.commons.utils.SessionUtils@getUserId()}'
</when>
<otherwise>
= #{${object}.value}
</otherwise>
</choose>
</sql>
<select id="list" resultType="io.metersphere.api.dto.delimit.ApiDelimitResult">
select api_delimit.id, api_delimit.project_id,
api_delimit.name,api_delimit.url,api_delimit.module_id,api_delimit.module_path,api_delimit.path,
api_delimit.description,api_delimit.request,
api_delimit.status, api_delimit.user_id, api_delimit.create_time, api_delimit.update_time, project.name as
project_name, user.name as user_name
from api_delimit
left join project on api_delimit.project_id = project.id
left join user on api_delimit.user_id = user.id
<where>
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
</include>
</if>
<if test="request.name != null">
and api_delimit.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.workspaceId != null">
AND project.workspace_id = #{request.workspaceId}
</if>
<if test="request.projectId != null">
AND project.id = #{request.projectId}
</if>
<if test="request.id != null">
AND api_delimit.id = #{request.id}
</if>
<if test="request.userId != null">
AND api_delimit.user_id = #{request.userId}
</if>
<if test="request.moduleId != null">
AND api_delimit.module_id = #{request.moduleId}
</if>
<if test="request.projectId != null">
AND api_delimit.project_id = #{request.projectId}
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
AND api_delimit.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
and api_delimit.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</if>
</foreach>
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
api_delimit.${order.name} ${order.type}
</foreach>
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiDelimitExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List"/>
from api_delimit
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List"/>
,
<include refid="Blob_Column_List"/>
from api_delimit
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from api_delimit
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.ApiDelimitExample">
delete from api_delimit
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiDelimit">
insert into api_delimit (id, project_id, name, url,module_id,module_path,path,
description, status, user_id,
create_time, update_time, request
)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{url,jdbcType=VARCHAR}, #{moduleId,jdbcType=VARCHAR},#{modulePath,jdbcType=VARCHAR},#{path,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{request,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiDelimit">
insert into api_delimit
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="projectId != null">
project_id,
</if>
<if test="name != null">
name,
</if>
<if test="url != null">
url,
</if>
<if test="path != null">
path,
</if>
<if test="moduleId != null">
module_id,
</if>
<if test="modulePath != null">
module_path,
</if>
<if test="description != null">
description,
</if>
<if test="status != null">
status,
</if>
<if test="userId != null">
user_id,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="request != null">
request,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="url != null">
#{url,jdbcType=VARCHAR},
</if>
<if test="moduleId != null">
#{moduleId,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=VARCHAR},
</if>
<if test="status != null">
#{status,jdbcType=VARCHAR},
</if>
<if test="userId != null">
#{userId,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="request != null">
#{request,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ApiDelimitExample"
resultType="java.lang.Long">
select count(*) from api_delimit
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update api_delimit
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
name = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.moduleId != null">
module_id = #{record.moduleId,jdbcType=BIGINT},
</if>
<if test="record.modulePath != null">
module_path = #{record.modulePath,jdbcType=BIGINT},
</if>
<if test="record.url != null">
url = #{record.url,jdbcType=LONGVARCHAR},
</if>
<if test="record.path != null">
path = #{record.path,jdbcType=LONGVARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=VARCHAR},
</if>
<if test="record.status != null">
status = #{record.status,jdbcType=VARCHAR},
</if>
<if test="record.userId != null">
user_id = #{record.userId,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.request != null">
request = #{record.request,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update api_delimit
set id = #{record.id,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
name = #{record.name,jdbcType=VARCHAR},
module_id = #{moduleId,jdbcType=VARCHAR},
module_path = #{modulePath,jdbcType=VARCHAR},
url = #{url,jdbcType=VARCHAR},
path = #{path,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
status = #{record.status,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
request = #{record.request,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
</update>
<update id="updateByExample" parameterType="map">
update api_delimit
set id = #{record.id,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
name = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
status = #{record.status,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiDelimit">
update api_delimit
<set>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="moduleId != null">
module_id = #{moduleId,jdbcType=BIGINT},
</if>
<if test="url != null">
url = #{url,jdbcType=LONGVARCHAR},
</if>
<if test="path != null">
path = #{path,jdbcType=VARCHAR},
</if>
<if test="modulePath != null">
module_path = #{modulePath,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=VARCHAR},
</if>
<if test="status != null">
status = #{status,jdbcType=VARCHAR},
</if>
<if test="userId != null">
user_id = #{userId,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="request != null">
request = #{request,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiDelimit">
update api_delimit
set project_id = #{projectId,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
status = #{status,jdbcType=VARCHAR},
user_id = #{userId,jdbcType=VARCHAR},
module_id = #{moduleId,jdbcType=VARCHAR},
module_path = #{modulePath,jdbcType=VARCHAR},
url = #{url,jdbcType=VARCHAR},
path = #{path,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
request = #{request,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiDelimit">
update api_delimit
set project_id = #{projectId,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
module_id = #{moduleId,jdbcType=VARCHAR},
url = #{url,jdbcType=VARCHAR},
module_path = #{modulePath,jdbcType=VARCHAR},
path = #{path,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
status = #{status,jdbcType=VARCHAR},
user_id = #{userId,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -0,0 +1,32 @@
package io.metersphere.base.mapper;
import io.metersphere.api.dto.delimit.ApiTestCaseRequest;
import io.metersphere.api.dto.delimit.ApiTestCaseResult;
import io.metersphere.base.domain.ApiTestCase;
import io.metersphere.base.domain.ApiTestCaseExample;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ApiTestCaseMapper {
List<ApiTestCaseResult> list(@Param("request") ApiTestCaseRequest request);
long countByExample(ApiTestCaseExample example);
int deleteByExample(ApiTestCaseExample example);
int deleteByPrimaryKey(String id);
int insert(ApiTestCase record);
List<ApiTestCase> selectByExampleWithBLOBs(ApiTestCaseExample example);
List<ApiTestCase> selectByExample(ApiTestCaseExample example);
ApiTestCase selectByPrimaryKey(String id);
int updateByPrimaryKeySelective(ApiTestCase record);
int updateByPrimaryKey(ApiTestCase record);
}

View File

@ -0,0 +1,281 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.ApiTestCaseMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiTestCase">
<id column="id" jdbcType="VARCHAR" property="id"/>
<result column="project_id" jdbcType="VARCHAR" property="projectId"/>
<result column="api_delimit_id" jdbcType="VARCHAR" property="apiDelimitId"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="priority" jdbcType="VARCHAR" property="priority"/>
<result column="description" jdbcType="VARCHAR" property="description"/>
<result column="create_user_id" jdbcType="VARCHAR" property="createUserId"/>
<result column="update_user_id" jdbcType="VARCHAR" property="updateUserId"/>
<result column="create_time" jdbcType="BIGINT" property="createTime"/>
<result column="update_time" jdbcType="BIGINT" property="updateTime"/>
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiTestCase">
<result column="request" jdbcType="LONGVARCHAR" property="request"/>
<result column="response" jdbcType="LONGVARCHAR" property="response"/>
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="("
separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="("
separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, project_id, name,api_delimit_id,priority,description, create_user_id, update_user_id, create_time, update_time
</sql>
<sql id="Blob_Column_List">
request
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.ApiTestCaseExample"
resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List"/>
,
<include refid="Blob_Column_List"/>
from api_test_case
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<sql id="condition">
<choose>
<when test='${object}.operator == "like"'>
like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "not like"'>
not like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "in"'>
in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "not in"'>
not in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "between"'>
between #{${object}.value[0]} and #{${object}.value[1]}
</when>
<when test='${object}.operator == "gt"'>
&gt; #{${object}.value}
</when>
<when test='${object}.operator == "lt"'>
&lt; #{${object}.value}
</when>
<when test='${object}.operator == "ge"'>
&gt;= #{${object}.value}
</when>
<when test='${object}.operator == "le"'>
&lt;= #{${object}.value}
</when>
<when test='${object}.operator == "current user"'>
= '${@io.metersphere.commons.utils.SessionUtils@getUserId()}'
</when>
<otherwise>
= #{${object}.value}
</otherwise>
</choose>
</sql>
<select id="list" resultType="io.metersphere.api.dto.delimit.ApiTestCaseResult">
select api_test_case.id, api_test_case.project_id,
api_test_case.name,api_test_case.priority,api_test_case.api_delimit_id,T1.name as createUser ,T2.name as
updateUser,
api_test_case.description,api_test_case.request,api_test_case.response,api_test_case.create_user_id,
api_test_case.create_time,api_test_case.update_user_id, api_test_case.update_time
from api_test_case left join user T1 on api_test_case.create_user_id = T1.id left join user T2 on
api_test_case.update_user_id = T2.id
<where>
<if test="request.name != null and request.name!=''">
and api_test_case.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.id != null and request.id!=''">
AND api_test_case.id = #{request.id}
</if>
<if test="request.priority != null and request.priority!=''">
AND api_test_case.priority = #{request.priority}
</if>
<if test="request.projectId != null and request.projectId!=''">
AND api_test_case.project_id = #{request.projectId}
</if>
<if test="request.apiDelimitId != null and request.apiDelimitId!=''">
AND api_test_case.api_delimit_id = #{request.apiDelimitId}
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
api_test_case.${order.name} ${order.type}
</foreach>
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiTestCaseExample"
resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List"/>
from api_test_case
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List"/>
,
<include refid="Blob_Column_List"/>
from api_test_case
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from api_test_case where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.ApiTestCaseExample">
delete from api_test_case
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiTestCase">
insert into api_test_case (id, project_id, name, priority,api_delimit_id,description, create_user_id, update_user_id,
create_time, update_time, request,response
)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{priority,jdbcType=VARCHAR}, #{apiDelimitId,jdbcType=VARCHAR},#{description,jdbcType=VARCHAR},
#{createUserId,jdbcType=VARCHAR}, #{updateUserId,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{request,jdbcType=LONGVARCHAR}, #{response,jdbcType=LONGVARCHAR})
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ApiTestCaseExample"
resultType="java.lang.Long">
select count(*) from api_test_case
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</select>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiTestCase">
update api_test_case
<set>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="apiDelimitId != null">
api_delimit_id = #{apiDelimitId,jdbcType=BIGINT},
</if>
<if test="priority != null">
priority = #{priority,jdbcType=LONGVARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=VARCHAR},
</if>
<if test="updateUserId != null">
update_user_id = #{updateUserId,jdbcType=VARCHAR},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="request != null">
request = #{request,jdbcType=LONGVARCHAR},
</if>
<if test="response != null">
request = #{response,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiTestCase">
update api_test_case
set project_id = #{projectId,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
api_delimit_id = #{apiDelimitId,jdbcType=VARCHAR},
priority = #{priority,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
update_user_id = #{updateUserId,jdbcType=VARCHAR},
update_time = #{updateTime,jdbcType=BIGINT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants;
public enum APITestStatus {
Saved, Starting, Running, Reporting, Completed, Debug, Error, Success
Saved, Starting, Running, Reporting, Completed, Debug, Error, Success,Underway
}

View File

@ -2,7 +2,8 @@
<ms-container>
<ms-aside-container>
<ms-node-tree></ms-node-tree>
<ms-node-tree @selectModule="selectModule" @getApiModuleTree="initTree"
@changeProject="changeProject"></ms-node-tree>
</ms-aside-container>
<ms-main-container>
@ -28,18 +29,16 @@
<ms-api-list
v-if="item.type === 'list'"
:current-project="currentProject"
:select-node-ids="selectApi"
:select-parent-nodes="selectParentNodes"
@testCaseEdit="editTestCase"
:current-module="currentModule"
@editApi="editApi"
@handleCase="handleCase"
@batchMove="batchMove"
@refresh="refresh"
@moveToNode="moveToNode"
ref="testCaseList">
ref="apiList">
</ms-api-list>
<div v-else-if="item.type=== 'add'">
<ms-api-config @runTest="runTest"></ms-api-config>
<ms-api-config @runTest="runTest" @saveApi="saveApi" :current-api="currentApi"
:currentProject="currentProject"
:moduleOptions="moduleOptions" ref="apiConfig"></ms-api-config>
</div>
<div v-else-if="item.type=== 'debug'">
<ms-debug-http-page @saveAs="saveAs"></ms-debug-http-page>
@ -66,6 +65,7 @@
import MsApiConfig from "./components/ApiConfig";
import MsDebugHttpPage from "./components/debug/DebugHttpPage";
import MsRunTestHttpPage from "./components/runtest/RunTestHttpPage";
import {getCurrentUser, getUUID} from "../../../../common/js/utils";
export default {
name: "TestCase",
@ -86,42 +86,34 @@
projectId: null,
isHide: true,
editableTabsValue: '1',
tabIndex: 1,
result: {},
currentPage: 1,
pageSize: 5,
total: 0,
currentProject: null,
currentModule: null,
currentApi: {},
moduleOptions: {},
editableTabs: [{
title: this.$t('api_test.delimit.api_title'),
name: '1',
type: "list",
closable: false
}],
tabIndex: 1,
result: {},
currentPage: 1,
pageSize: 5,
total: 0,
projects: [],
currentProject: null,
treeNodes: [],
selectApi: {},
selectParentNodes: [],
testCaseReadOnly: true,
selectNode: {},
nodeTreeDraggable: true,
}
},
created() {
},
watch: {
'$route': 'init',
},
methods: {
handleCommand(e) {
if (e === "add") {
this.currentApi = {
status: "Underway",
path: "GET",
userId: getCurrentUser().id,
};
this.handleTabsEdit(this.$t('api_test.delimit.request.title'), e);
} else if (e === "test") {
}
else if (e === "test") {
this.handleTabsEdit(this.$t("commons.api"), e);
}
else if (e === "closeAll") {
@ -154,45 +146,56 @@
if (targetName === undefined || targetName === null) {
targetName = this.$t('api_test.delimit.request.title');
}
let newTabName = ++this.tabIndex + '';
let newTabName = getUUID().substring(0, 8);
this.editableTabs.push({
title: targetName,
name: newTabName,
closable: true,
type: action,
content: MsApiConfig
type: action
});
this.editableTabsValue = newTabName;
}
},
editTestCase(testCase) {
this.handleTabsEdit(testCase.api_name, "add");
editApi(row) {
this.currentApi = row;
this.handleTabsEdit(row.name, "add");
},
handleCase(testCase) {
this.selectApi = testCase;
this.currentApi = testCase;
this.isHide = false;
},
apiCaseClose() {
this.isHide = true;
},
batchMove(selectIds) {
selectModule(data) {
this.currentModule = data;
},
refresh() {
},
moveToNode() {
refresh(data) {
this.$refs.apiList[0].initTableData(data);
},
saveAs(data) {
this.handleCommand("add");
},
runTest(data) {
console.log(data);
this.handleCommand("test");
},
search() {
alert(1);
saveApi(data) {
for (let index in this.editableTabs) {
let tab = this.editableTabs[index];
if (tab.name === this.editableTabsValue) {
tab.title = data.name;
break;
}
}
this.$refs.apiList[0].initTableData(data);
},
initTree(data) {
this.moduleOptions = data;
},
changeProject(data) {
this.currentProject = data;
}
}
}

View File

@ -1,11 +1,11 @@
<template>
<div v-loading="result.loading">
<div>
<el-container>
<el-header style="width: 100% ;padding: 0px">
<el-card>
<el-row>
<el-col :span="3">
<div class="variable-combine"> {{api.api_name}}</div>
<div class="variable-combine"> {{api.name}}</div>
</el-col>
<el-col :span="1">
<template>
@ -20,7 +20,7 @@
</template>
</el-col>
<el-col :span="4">
<div class="variable-combine">{{api.api_path}}</div>
<div class="variable-combine">{{api.url}}</div>
</el-col>
<el-col :span="2">
<div>{{$t('test_track.plan_view.case_count')}}5</div>
@ -28,25 +28,39 @@
<el-col :span="4">
<div>
<el-select size="small" :placeholder="$t('api_test.delimit.request.grade_info')" v-model="grdValue"
class="ms-api-header-select">
<el-option v-for="grd in grades" :key="grd.id" :label="grd.name" :value="grd.id"/>
class="ms-api-header-select" @change="getApiTest">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</div>
</el-col>
<el-col :span="4">
<div>
<el-select size="small" class="ms-api-header-select" v-model="envValue"
:placeholder="$t('api_test.delimit.request.run_env')">
<el-option v-for="env in environments" :key="env.id" :label="env.name" :value="env.id"/>
<el-select :disabled="isReadOnly" v-model="envValue" size="small" class="ms-api-header-select"
:placeholder="$t('api_test.delimit.request.run_env')"
@change="environmentChange" clearable>
<el-option v-for="(environment, index) in environments" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/>
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
<template v-slot:empty>
<div class="empty-environment">
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
</div>
</template>
</el-select>
</div>
</el-col>
<el-col :span="3">
<div class="ms-api-header-select">
<el-input size="small" :placeholder="$t('api_test.delimit.request.select_case')"></el-input>
<el-input size="small" :placeholder="$t('api_test.delimit.request.select_case')"
v-model="name" @blur="getApiTest"/>
</div>
</el-col>
<el-col :span="1">
<el-col :span="2">
<div class="ms-api-header-select">
<el-button size="small" @click="createCase">+{{$t('api_test.delimit.request.case')}}</el-button>
</div>
@ -57,6 +71,10 @@
</el-col>
</el-row>
</el-card>
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
</el-header>
@ -78,17 +96,15 @@
</el-col>
<el-col :span="10">
<i class="icon el-icon-arrow-right" :class="{'is-active': item.isActive}"
<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"/>
:key="index" class="ms-api-header-select" style="width: 180px"/>
{{item.type!= 'create'? item.name : ''}}
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
{{item.create_time}}
{{item.create_user}} 创建
{{item.update_time}}
{{item.update_user}} 更新
<span> {{item.createTime | timestampFormatDate }}</span> {{item.createUser}} 创建
<span> {{item.updateTime | timestampFormatDate }}</span> {{item.updateUser}} 更新
</div>
</el-col>
<el-col :span="4">
@ -96,63 +112,71 @@
style="background-color: #409EFF;color: white" size="mini" circle/>
<ms-tip-button @click="copyCase(item)" :tip="$t('commons.copy')" icon="el-icon-document-copy"
size="mini" circle/>
<ms-tip-button @click="deleteCase(index)" :tip="$t('commons.delete')" icon="el-icon-delete" size="mini"
<ms-tip-button @click="deleteCase(index,item)" :tip="$t('commons.delete')" icon="el-icon-delete"
size="mini"
circle/>
</el-col>
<el-col :span="4">
<div v-if="item.type!='create'">{{getResult(item.execute_result)}}</div>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">{{item.update_time}}
{{item.update_user}}
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span> {{item.updateTime | timestampFormatDate }}</span>
{{item.updateUser}}
</div>
</el-col>
</el-row>
<!-- 请求参数-->
<el-collapse-transition>
<div v-show="item.isActive">
<ms-api-request-form :debug-report-id="debugReportId" @runDebug="runDebug"
:request="selected" :scenario="currentScenario" v-if="handleChange"/>
<div v-if="item.active">
<ms-api-request-form :is-read-only="isReadOnly" :debug-report-id="debugReportId" @runDebug="runDebug"
:request="item.test.request"/>
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)">
{{$t('commons.save')}}
</el-button>
</div>
</el-collapse-transition>
</el-card>
</div>
<el-button type="primary" size="small" style="margin-top: 20px; float: right">{{$t('commons.save')}}</el-button>
</el-main>
</el-container>
</div>
</template>
<script>
import MsTag from "../../../common/components/MsTag";
import MsTipButton from "../../../common/components/MsTipButton";
import MsApiRequestForm from "./request/ApiRequestForm";
import {Request, Scenario} from "../model/ScenarioModel";
import {Test, RequestFactory} from "../model/ScenarioModel";
import {downloadFile, getUUID} from "@/common/js/utils";
import {parseEnvironment} from "../model/EnvironmentModel";
import ApiEnvironmentConfig from "../../test/components/ApiEnvironmentConfig";
export default {
name: 'ApiCaseList',
components: {
MsTag,
MsTipButton,
MsApiRequestForm
MsApiRequestForm,
ApiEnvironmentConfig
},
props: {
api: {
type: Object
},
currentProject: {},
},
data() {
return {
result: {},
grades: [],
environments: [],
envValue: "",
envValue: {},
grdValue: "",
value: "",
isReadOnly: false,
name: "",
priority: [
{name: 'P0', id: 'P0'},
{name: 'P1', id: 'P1'},
@ -160,39 +184,29 @@
{name: 'P3', id: 'P3'}
],
apiCaseList: [],
reportVisible: false,
create: false,
projects: [],
change: false,
isReadOnly: false,
debugReportId: '',
type: "",
activeName: 0,
selected: [Scenario, Request],
currentScenario: {}
debugReportId: ''
}
},
watch: {
//
api() {
let obj = {
name: '测试用例',
priority: 'P0',
execute_result: 'PASS',
create_time: '2020-11-1: 10:05',
update_time: '2020-11-1: 10:05',
create_user: '赵勇',
isActive: false,
update_user: '赵勇'
};
this.apiCaseList.push(obj);
this.getApiTest();
},
currentProject() {
this.getEnvironments();
}
},
methods: {
getRequest(request) {
if (request === undefined || request === null) {
this.test = new Test();
this.test.request.environment = this.envValue;
return this.test.request;
} else {
return new RequestFactory(JSON.parse(request));
}
},
getResult(data) {
if (data === 'PASS') {
return '执行结果:通过';
@ -208,37 +222,148 @@
},
runCase() {
},
deleteCase(index) {
this.apiCaseList.splice(index, 1);
deleteCase(index, row) {
this.$get('/api/testcase/delete/' + row.id, () => {
this.$success(this.$t('commons.delete_success'));
this.apiCaseList.splice(index, 1);
});
},
copyCase(data) {
let obj = {
name: data.name,
priority: data.priority,
type: 'create'
type: 'create',
active: false,
test: data.test,
};
this.apiCaseList.push(obj);
},
createCase() {
let test = new Test();
let obj = {
id: this.apiCaseList.size + 1,
name: '',
priority: 'P0',
type: 'create',
isActive: true,
active: false,
test: test,
};
this.apiCaseList.push(obj);
},
runDebug() {
},
handleChange(v) {
return v != "";
},
active(item) {
item.isActive = !item.isActive;
item.active = !item.active;
},
getBodyUploadFiles(row) {
let bodyUploadFiles = [];
row.bodyUploadIds = [];
let request = row.test.request;
if (request.body) {
request.body.kvs.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
let fileId = getUUID().substring(0, 8);
item.name = item.file.name;
item.id = fileId;
row.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
return bodyUploadFiles;
},
getApiTest() {
let condition = {};
condition.projectId = this.api.projectId;
condition.apiDelimitId = this.api.id;
condition.priority = this.grdValue;
condition.name = this.name;
this.result = this.$post("/api/testcase/list", condition, response => {
for (let index in response.data) {
let test = response.data[index];
test.test = new Test({request: new RequestFactory(JSON.parse(test.request))});
}
this.apiCaseList = response.data;
});
},
validate(row) {
if (!row.name) {
this.$warning(this.$t('api_test.input_name'));
return true;
}
},
saveTestCase(row) {
if (this.validate(row)) {
return;
}
let bodyFiles = this.getBodyUploadFiles(row);
row.test.request.url = this.api.url;
row.test.request.path = this.api.path;
row.projectId = this.api.projectId;
row.apiDelimitId = this.api.id;
row.request = row.test.request;
let jmx = row.test.toJMX();
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
let file = new File([blob], jmx.name);
let url = "/api/testcase/create";
if (row.id) {
url = "/api/testcase/update";
}
this.$fileUpload(url, file, bodyFiles, row, () => {
this.$success(this.$t('commons.save_success'));
this.getApiTest();
});
},
getEnvironments() {
if (this.currentProject) {
this.result = this.$get('/api/environment/list/' + this.currentProject.id, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
});
} else {
this.api.environmentId = '';
this.api.environment = undefined;
}
},
openEnvironmentConfig() {
if (!this.currentProject) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
},
environmentChange(value) {
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.api.environment = this.environments[i];
break;
}
}
},
environmentConfigClose() {
this.getEnvironments();
}
}
}
</script>
@ -251,13 +376,12 @@
.ms-api-header-select {
margin-left: 20px;
width: 150px;
}
.el-card-btn {
float: right;
top: 20px;
right: 20px;
right: 0px;
padding: 0;
background: 0 0;
border: none;
@ -278,19 +402,6 @@
color: white;
}
.ms-ap-collapse {
padding-top: 0px;
border: 0px;
}
/deep/ .el-collapse-item__header {
border-bottom: 0px;
margin-top: 0px;
width: 300px;
line-height: 0px;
color: #666666;
}
.variable-combine {
overflow: hidden;
text-overflow: ellipsis;

View File

@ -1,13 +1,16 @@
<template>
<div class="card-container">
<ms-add-complete-http-api @runTest="runTest" :httpData="result" v-if="reqType === 'HTTP'"></ms-add-complete-http-api>
<ms-add-complete-http-api @runTest="runTest" @saveApi="saveApi" :httpData="currentApi" :test="test"
:moduleOptions="moduleOptions" :currentProject="currentProject"
v-if="reqType === 'HTTP'"></ms-add-complete-http-api>
</div>
</template>
<script>
import MsAddCompleteHttpApi from "./complete/AddCompleteHttpApi";
import {RequestFactory} from "../model/ScenarioModel";
import {RequestFactory, Test} from "../model/ScenarioModel";
import {downloadFile, getUUID} from "@/common/js/utils";
export default {
name: "ApiConfig",
@ -15,13 +18,68 @@
data() {
return {
reqType: RequestFactory.TYPES.HTTP,
result: {},
test: new Test(),
postUrl: "",
}
},
props: {
currentApi: {},
moduleOptions: {},
currentProject: {},
},
created() {
if (this.currentApi != null && this.currentApi.id != null) {
let item = this.currentApi;
this.test = new Test({
id: item.id,
projectId: item.projectId,
name: item.name,
status: item.status,
path: item.path,
request: new RequestFactory(JSON.parse(item.request)),
});
this.postUrl = "/api/delimit/update";
} else {
this.test = new Test();
this.postUrl = "/api/delimit/create";
}
},
props: {},
methods: {
runTest(data){
this.$emit('runTest',data);
runTest(data) {
this.$emit('runTest', data);
},
getBodyUploadFiles() {
let bodyUploadFiles = [];
this.test.bodyUploadIds = [];
let request = this.test.request;
if (request.body) {
request.body.kvs.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
let fileId = getUUID().substring(0, 8);
item.name = item.file.name;
item.id = fileId;
this.test.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
return bodyUploadFiles;
},
saveApi(data) {
this.test = data;
let bodyFiles = this.getBodyUploadFiles();
let jmx = this.test.toJMX();
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
let file = new File([blob], jmx.name);
this.$fileUpload(this.postUrl, file, bodyFiles, this.test, () => {
this.$success(this.$t('commons.save_success'));
this.$emit('saveApi', this.test);
this.postUrl = "/api/delimit/update";
});
}
}
}

View File

@ -15,12 +15,12 @@
class="test-content adjust-table">
<el-table-column
prop="api_name"
prop="name"
:label="$t('api_test.delimit.api_name')"
show-overflow-tooltip/>
<el-table-column
prop="api_status"
prop="status"
column-key="api_status"
:label="$t('api_test.delimit.api_status')"
show-overflow-tooltip>
@ -28,11 +28,11 @@
<span class="el-dropdown-link">
<template>
<div>
<ms-tag v-if="scope.row.api_status == 'Prepare'" type="info"
<ms-tag v-if="scope.row.status == 'Prepare'" type="info"
:content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="scope.row.api_status == 'Underway'" type="primary"
<ms-tag v-if="scope.row.status == 'Underway'" type="primary"
:content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="scope.row.api_status == 'Completed'" type="success"
<ms-tag v-if="scope.row.status == 'Completed'" type="success"
:content="$t('test_track.plan.plan_status_completed')"/>
</div>
</template>
@ -41,7 +41,7 @@
</el-table-column>
<el-table-column
prop="api_type"
prop="path"
:label="$t('api_test.delimit.api_type')"
show-overflow-tooltip>
<template v-slot:default="scope">
@ -49,7 +49,7 @@
<template>
<div class="request-method">
<el-tag size="mini"
:style="{'background-color': getColor(true, scope.row.api_type)}" class="api-el-tag"> {{ scope.row.api_type }}</el-tag>
:style="{'background-color': getColor(true, scope.row.path)}" class="api-el-tag"> {{ scope.row.path }}</el-tag>
</div>
</template>
</span>
@ -58,32 +58,33 @@
</el-table-column>
<el-table-column
prop="api_path"
prop="url"
:label="$t('api_test.delimit.api_path')"
show-overflow-tooltip/>
<el-table-column
prop="api_principal"
prop="userName"
:label="$t('api_test.delimit.api_principal')"
show-overflow-tooltip/>
<el-table-column
prop="api_last_time"
:label="$t('api_test.delimit.api_last_time')"
show-overflow-tooltip/>
<el-table-column width="200" :label="$t('api_test.delimit.api_last_time')" prop="updateTime">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
prop="api_case_number"
prop="caseTotal"
:label="$t('api_test.delimit.api_case_number')"
show-overflow-tooltip/>
<el-table-column
prop="api_case_status"
prop="caseStatus"
:label="$t('api_test.delimit.api_case_status')"
show-overflow-tooltip/>
<el-table-column
prop="api_case_passing_rate"
prop="casePassingRate"
:label="$t('api_test.delimit.api_case_passing_rate')"
show-overflow-tooltip/>
@ -91,7 +92,7 @@
<el-table-column
:label="$t('commons.operating')" min-width="100">
<template v-slot:default="scope">
<el-button type="text" @click="testCaseEdit(scope.row)">编辑</el-button>
<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>
</template>
@ -104,7 +105,7 @@
</el-card>
<ms-bottom-container v-bind:enableAsideHidden="isHide">
<ms-api-case-list @apiCaseClose="apiCaseClose" :api="selectApi"></ms-api-case-list>
<ms-api-case-list @apiCaseClose="apiCaseClose" :api="selectApi" :current-project="currentProject"/>
</ms-bottom-container>
</div>
@ -116,13 +117,13 @@
import MsTableOperator from "../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
import MsTableButton from "../../../common/components/MsTableButton";
import {TEST_CASE_CONFIGS} from "../../../common/components/search/search-components";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
import MsTablePagination from "../../../common/pagination/TablePagination";
import MsTag from "../../../common/components/MsTag";
import MsApiCaseList from "./ApiCaseList";
import MsContainer from "../../../common/components/MsContainer";
import MsBottomContainer from "./BottomContainer";
import {Message} from "element-ui";
export default {
name: "ApiList",
@ -143,6 +144,7 @@
condition: {},
isHide: true,
selectApi: {},
moduleId: "",
deletePath: "/test/case/delete",
methodColorMap: new Map([
['GET', "#61AFFE"], ['POST', '#49CC90'], ['PUT', '#fca130'],
@ -150,37 +152,7 @@
['HEAD', '#8E58E7'], ['CONNECT', '#90AFAE'],
['DUBBO', '#C36EEF'], ['SQL', '#0AEAD4'], ['TCP', '#0A52DF'],
]),
tableData: [{
api_name: "接口名称",
api_status: "Completed",
api_type: "GET",
api_path: "/api/common/login.do",
api_principal: "负责人",
api_last_time: "最后更新时间",
api_case_number: "用例数",
api_case_status: "失败",
api_case_passing_rate: "100%"
}, {
api_name: "接口名称",
api_status: "Prepare",
api_type: "GET",
api_path: "/api/common/login.do",
api_principal: "负责人",
api_last_time: "最后更新时间",
api_case_number: "用例数",
api_case_status: "通过",
api_case_passing_rate: "100%"
}, {
api_name: "接口名称",
api_status: "Underway",
api_type: "POST",
api_path: "/api/common/login.do",
api_principal: "负责人",
api_last_time: "最后更新时间",
api_case_number: "用例数",
api_case_status: "通过",
api_case_passing_rate: "-"
}],
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
@ -190,9 +162,7 @@
currentProject: {
type: Object
},
selectParentNodes: {
type: Array
}
currentModule: Object
},
created: function () {
this.initTableData();
@ -201,36 +171,50 @@
currentProject() {
this.initTableData();
},
currentModule() {
this.initTableData();
}
},
methods: {
initTableData() {
if (this.currentModule != null) {
if (this.currentModule.id == "rootID") {
this.condition.moduleIds = [];
} else {
this.condition.moduleIds = this.currentModule.ids;
}
}
if (this.currentProject != null) {
this.condition.projectId = this.currentProject.id;
}
this.result = this.$post("/api/delimit/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
});
},
search() {
alert("s");
this.initTableData();
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
testCaseEdit(testCase) {
this.$emit('testCaseEdit', testCase);
editApi(row) {
this.$emit('editApi', row);
},
handleTestCase(testCase) {
this.selectApi = testCase;
this.isHide = false;
},
handleDelete(testCase) {
this.$get('/api/delimit/delete/' + testCase.id, () => {
Message.success(this.$t('commons.delete_success'));
this.initTableData();
});
},
apiCaseClose() {
this.isHide = true;
},
refresh() {
this.condition = {components: TEST_CASE_CONFIGS};
// this.selectIds.clear();
this.selectRows.clear();
this.$emit('refresh');
},
getColor(enable, method) {
if (enable) {
return this.methodColorMap.get(method);

View File

@ -10,7 +10,7 @@
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:name="item.name"
:value="item.value"
:disabled="item.disabled">
</el-option>
@ -25,18 +25,16 @@
<el-tree :data="data"
class="filter-tree node-tree"
node-key="id"
default-expand-all
:default-expanded-keys="expandedNode"
:expand-on-click-node="false"
@node-click="nodeClick"
@node-drag-start="handleDragStart"
@node-drag-enter="handleDragEnter"
@node-drag-leave="handleDragLeave"
@node-drag-over="handleDragOver"
@node-expand="nodeExpand"
@node-collapse="nodeCollapse"
@node-click="selectModule"
@node-drag-end="handleDragEnd"
@node-drop="handleDrop"
:filter-node-method="filterNode"
draggable
:allow-drop="allowDrop"
:allow-drag="allowDrag">
:allow-drag="allowDrag" ref="tree">
<span class="custom-tree-node father"
slot-scope="{ node, data }">
<!-- 如果是编辑状态 -->
@ -47,11 +45,11 @@
class="ms-el-input" size="mini"></el-input>
</template>
<!-- 如果不是编辑状态 -->
<span class="node-title" v-else v-text="data.label"></span>
<span class="node-title" v-else v-text="data.name"></span>
<span class="node-operate child">
<el-tooltip
v-if="data.id!=1"
v-if="data.id!='rootID'"
class="item"
effect="dark"
:open-delay="200"
@ -70,7 +68,7 @@
</el-tooltip>
<el-tooltip
v-if="data.id!=1"
v-if="data.id!='rootID'"
class="item"
effect="dark"
:open-delay="200"
@ -102,19 +100,20 @@
return {
options: [{
value: 'HTTP',
label: 'HTTP'
name: 'HTTP'
}, {
value: 'DUBBO',
label: 'DUBBO'
name: 'DUBBO'
}, {
value: 'TCP',
label: 'TCP'
name: 'TCP'
}, {
value: 'SQL',
label: 'SQL'
name: 'SQL'
}],
value: 'HTTP',
httpVisible: false,
expandedNode: [],
result: {},
filterText: "",
nextFlag: true,
@ -122,82 +121,142 @@
projects: [],
data: [
{
"id": 1,
"label": "技术部",
"level": 1,
"children": [
{
"id": 2,
"label": "运维组",
"level": 2,
"children": [
{
"id": 3,
"label": "godo",
"level": 3,
"children": []
}
]
},
{
"id": 4,
"label": "测试组",
"level": 2,
"children": []
}
]
"id": "rootID",
"name": "默认模块",
"level": 0,
"children": [],
}
],
newLabel: '',
defaultProps: {
children: 'children',
label: 'label'
}
currentModule: {},
newLabel: ""
}
},
created() {
this.getApiGroupData()
},
watch: {
currentProject() {
this.getApiModuleTree();
this.$emit('changeProject', this.currentProject);
},
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
getApiModuleTree() {
if (this.currentProject) {
this.result = this.$get("/api/module/list/" + this.currentProject.id + "/" + this.value, response => {
this.data = response.data;
if (response.data != undefined && response.data != null) {
this.data[0].children = response.data;
let moduleOptions = [];
this.data[0].children.forEach(node => {
this.buildNodePath(node, {path: ''}, moduleOptions);
});
this.$emit('getApiModuleTree', moduleOptions);
}
});
}
},
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);
}
}
},
// api
getApiGroupData() {
this.getProjects();
this.getApiModuleTree();
},
handleDragStart(node, ev) {
console.log('drag start', node.data.label)
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;
}
}
}
},
handleDragEnter(draggingNode, dropNode, ev) {
console.log('tree drag enter: ', dropNode.data.label)
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;
} 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;
}
}
}
param.nodeIds = nodeIds;
return param;
},
handleDragLeave(draggingNode, dropNode, ev) {
console.log('tree drag leave: ', dropNode.data.label)
},
handleDragOver(draggingNode, dropNode, ev) {
console.log('tree drag over: ', dropNode.data.label)
getNodeTree(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.getNodeTree(nodes[i].children, id, list);
}
}
},
handleDragEnd(draggingNode, dropNode, dropType, ev) {
console.log(
'tree drag end: ',
dropNode && dropNode.data.label,
dropType
)
//
this.updateApiGroup(this.data)
},
handleDrop(draggingNode, dropNode, dropType, ev) {
console.log('tree drop: ', dropNode.data.label, dropType)
if (dropNode.data.id === "rootID" || dropType === "none" || dropType === undefined) {
return;
}
let param = this.buildParam(draggingNode, dropNode, dropType);
this.list = [];
if (param.parentId === "rootID") {
param.parentId = null;
}
this.getNodeTree(this.data, draggingNode.data.id, this.list);
this.$post("/api/module/drag", param, () => {
this.getApiGroupData();
}, (error) => {
this.getApiGroupData();
});
},
allowDrop(draggingNode, dropNode, type) {
if (dropNode.data.id === 1) {
if (dropNode.data.id === "rootID") {
return false
} else {
return true
@ -205,7 +264,7 @@
},
allowDrag(draggingNode) {
//
if (draggingNode.data.id === 1) {
if (draggingNode.data.id === "rootID") {
return false
} else {
return true
@ -213,139 +272,158 @@
},
append(node, data) {
// var pid = data.parentApiGroupId + ':' + data.id
if (this.nextFlag) {
var timestamp = new Date().getTime()
if (this.nextFlag === true) {
const newChild = {
id: timestamp,
id: "newId",
isEdit: 0,
label: '',
name: "",
children: []
}
if (!data.children) {
this.$set(data, 'children', [])
}
this.nextFlag = false;
data.children.push(newChild)
this.updateApiGroup(this.data)
this.edit(node, newChild);
} else {
this.$message.warning(this.$t('commons.please_save'));
}
},
remove(node, data) {
if (data.label === "") {
if (data.name === "") {
this.nextFlag = true;
}
const parent = node.parent
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.id === data.id)
children.splice(index, 1)
this.updateApiGroup(this.data)
let delIds = [];
this.getChildNodeId(data, delIds);
delIds.push(data.id);
this.$post("/api/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.label
this.newLabel = data.name
this.$nextTick(() => {
this.$refs.input.focus()
//this.$refs.input.focus();
})
console.log('after:', data.id, data.label, data.isEdit)
},
submitEdit(node, data) {
//
if (this.newLabel === "") {
this.nextFlag = false;
this.$message.warning(this.$t('commons.input_name'));
return;
}
if (data.label == this.newLabel) {
this.newLabel = ''
this.$set(data, 'isEdit', 0)
} else {
this.$set(data, 'label', this.newLabel)
this.newLabel = ''
this.$set(data, 'isEdit', 0)
this.updateApiGroup(node, data);
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.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);
}
}
},
//
updateApiGroup(node, data) {
let url = '';
if (!data.id) {
editApiModule(node, data) {
let url = "";
if (data.id === "newId") {
url = '/api/module/add';
data.level = 1;
if (node.parent) {
//
data.parentId = node.parent.id;
data.level = node.parent.level + 1;
if (node.parent && node.parent.key != "rootID") {
data.parentId = node.parent.key;
data.level = node.parent.level;
}
} else if (this.type === 'edit') {
} else {
url = '/api/module/edit';
data.id = this.node.id;
data.level = this.node.level;
data.nodeIds = this.nodeIds;
let ids = [];
this.getChildNodeId(data, ids);
data.nodeIds = ids;
}
data.name = data.label;
data.protocol = this.value;
data.projectId = this.currentProject.id;
this.$post(url, data, () => {
this.$success(this.$t('commons.save_success'));
this.getApiGroupData();
this.nextFlag = true;
return true;
});
return false;
},
nodeClick(node, data, obj) {
console.log('点击了:', node.id, node.label)
selectModule(data) {
if (data.id != "rootID") {
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);
},
filterNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
addApi() {
this.$refs.httpApi.open();
this.$refs.httpApi.open(this.currentModule, this.currentProject.id);
},
//
changeProject(project) {
this.setCurrentProject(project);
},
setCurrentProject(project) {
if (project) {
this.currentProject = project;
localStorage.setItem("current_project", JSON.stringify(project));
}
//
this.currentProject = project;
},
getProjects() {
let projectId;
this.$get("/project/listAll", (response) => {
this.projects = response.data;
let lastProject = JSON.parse(localStorage.getItem("current_project"));
if (lastProject) {
let hasCurrentProject = false;
for (let i = 0; i < this.projects.length; i++) {
if (this.projects[i].id == lastProject.id) {
this.currentProject = lastProject;
hasCurrentProject = true;
break;
}
}
if (!hasCurrentProject) {
this.setCurrentProject(this.projects[0]);
}
} else {
if (this.projects.length > 0) {
this.setCurrentProject(this.projects[0]);
}
if (this.projects.length > 0) {
this.currentProject = this.projects[0];
}
});
},
nodeExpand(data) {
if (data.id) {
this.expandedNode.push(data.id);
}
},
nodeCollapse(data) {
if (data.id) {
this.expandedNode.splice(this.expandedNode.indexOf(data.id), 1);
}
}
}
}
</script>

View File

@ -67,7 +67,7 @@
<script>
import {KeyValue, Scenario} from "../model/ScenarioModel";
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
import MsApiVariableAdvance from "@/business/components/api/test/components/ApiVariableAdvance";
import MsApiVariableAdvance from "./ApiVariableAdvance";
import MsApiBodyFileUpload from "./body/ApiBodyFileUpload";
export default {
@ -78,6 +78,7 @@
valuePlaceholder: String,
description: String,
parameters: Array,
rest: Array,
environment: Object,
scenario: Scenario,
type: {

View File

@ -0,0 +1,282 @@
<template>
<el-dialog :title="$t('api_test.request.parameters_advance')"
:visible.sync="itemValueVisible"
class="advanced-item-value"
width="70%">
<el-tabs tab-position="top" style="height: 50vh;" @tab-click="selectTab">
<el-tab-pane :label="$t('api_test.request.parameters_advance_mock')">
<el-row type="flex" :gutter="20">
<el-col :span="6" class="col-height">
<div>
<el-input size="small" v-model="filterText"
:placeholder="$t('api_test.request.parameters_mock_filter_tips')"/>
<el-tree class="filter-tree" ref="tree" :data="mockFuncs" :props="treeProps"
default-expand-all @node-click="selectVariable"
:filter-node-method="filterNode"></el-tree>
</div>
</el-col>
<el-col :span="6" v-for="(itemFunc, itemIndex) in mockVariableFuncs" :key="itemIndex">
<div v-for="(func, funcIndex) in funcs"
:key="`${itemIndex}-${funcIndex}`">
<el-row>
<el-col :span="12">
<el-radio size="mini" v-model="itemFunc.name" :label="func.name"
@change="methodChange(itemFunc, func)"/>
</el-col>
<el-col :span="12" v-if="itemFunc.name === func.name">
<div v-for="(p, pIndex) in itemFunc.params" :key="`${itemIndex}-${funcIndex}-${pIndex}`">
<el-input :placeholder="p.name" size="mini" v-model="p.value" @change="showPreview"/>
</div>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.variable')">
<el-row>
<el-col :span="6" class="col-height">
<div v-if="environment">
<p>{{ $t('api_test.environment.environment') }}</p>
<el-tree :data="environmentParams" :props="treeProps" @node-click="selectVariable"></el-tree>
</div>
<div v-if="scenario">
<p>{{ $t('api_test.scenario.scenario') }}</p>
<el-tree :data="scenarioParams" :props="treeProps" @node-click="selectVariable"></el-tree>
</div>
<div v-if="preRequestParams">
<p>{{ $t('api_test.request.parameters_pre_request') }}</p>
<el-tree :data="preRequestParams" :props="treeProps" @node-click="selectVariable"></el-tree>
</div>
</el-col>
<el-col :span="18" class="col-height">
<div>
<h1>{{ $t('api_test.request.jmeter_func') }}</h1>
<el-table border :data="jmeterFuncs" class="adjust-table table-content" height="400">
<el-table-column prop="type" label="Type" width="150"/>
<el-table-column prop="name" label="Functions" width="250"/>
<el-table-column prop="description" label="Description"/>
</el-table>
</div>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
<el-form>
<el-form-item>
<el-input :placeholder="valueText" size="small"
v-model="itemValue"/>
</el-form-item>
</el-form>
<div style="padding-top: 10px;">
<el-row type="flex" align="middle">
<el-col :span="12">
<el-button size="small" type="primary" plain @click="saveAdvanced()">
{{ $t('commons.save') }}
</el-button>
<el-button size="small" type="info" plain @click="addFunc()" v-if="currentTab === 0">
{{ $t('api_test.request.parameters_advance_add_func') }}
</el-button>
<el-button size="small" type="success" plain @click="showPreview()" v-if="currentTab === 0">
{{ $t('api_test.request.parameters_preview') }}
</el-button>
</el-col>
<el-col>
<div> {{ itemValuePreview }}</div>
</el-col>
</el-row>
</div>
</el-dialog>
</template>
<script>
import {calculate, Scenario} from "../model/ScenarioModel";
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
export default {
name: "MsApiVariableAdvance",
props: {
parameters: Array,
environment: Object,
scenario: Scenario,
currentItem: Object,
},
data() {
return {
itemValueVisible: false,
filterText: '',
environmentParams: [],
scenarioParams: [],
preRequests: [],
preRequestParams: [],
treeProps: {children: 'children', label: 'name'},
currentTab: 0,
itemValue: null,
itemValuePreview: null,
funcs: [
{name: "md5"},
{name: "base64"},
{name: "unbase64"},
{
name: "substr",
params: [{name: "start"}, {name: "length"}]
},
{
name: "concat",
params: [{name: "suffix"}]
},
{name: "lconcat", params: [{name: "prefix"}]},
{name: "sha1"},
{name: "sha224"},
{name: "sha256"},
{name: "sha384"},
{name: "sha512"},
{name: "lower"},
{name: "upper"},
{name: "length"},
{name: "number"}
],
mockFuncs: MOCKJS_FUNC.map(f => {
return {name: f.name, value: f.name}
}),
jmeterFuncs: JMETER_FUNC,
mockVariableFuncs: [],
jmeterVariableFuncs: [],
}
},
computed: {
valueText() {
return this.valuePlaceholder || this.$t("api_test.value");
}
},
mounted() {
this.prepareData();
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
},
methods: {
open() {
this.itemValueVisible = true;
},
prepareData() {
if (this.scenario) {
let variables = this.scenario.variables;
this.scenarioParams = [
{
name: this.scenario.name,
children: variables.filter(v => v.name).map(v => {
return {name: v.name, value: '${' + v.name + '}'}
}),
}
];
if (this.environment) {
let variables = this.environment.config.commonConfig.variables;
this.environmentParams = [
{
name: this.environment.name,
children: variables.filter(v => v.name).map(v => {
return {name: v.name, value: '${' + v.name + '}'}
}),
}
];
}
let i = this.scenario.requests.indexOf(this.request);
this.preRequests = this.scenario.requests.slice(0, i);
this.preRequests.forEach(r => {
let js = r.extract.json.map(v => {
return {name: v.variable, value: v.value}
});
let xs = r.extract.xpath.map(v => {
return {name: v.variable, value: v.value}
});
let rx = r.extract.regex.map(v => {
return {name: v.variable, value: v.value}
});
let vs = [...js, ...xs, ...rx];
if (vs.length > 0) {
this.preRequestParams.push({name: r.name, children: vs});
}
});
}
},
filterNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
selectVariable(node) {
this.itemValue = node.value;
},
selectTab(tab) {
this.currentTab = +tab.index;
this.itemValue = null;
this.itemValuePreview = null;
},
showPreview() {
//
if (!this.itemValue) {
return;
}
let index = this.itemValue.indexOf("|");
if (index > -1) {
this.itemValue = this.itemValue.substring(0, index).trim();
}
this.mockVariableFuncs.forEach(f => {
if (!f.name) {
return;
}
this.itemValue += "|" + f.name;
if (f.params) {
this.itemValue += ":" + f.params.map(p => p.value).join(",");
}
});
this.itemValuePreview = calculate(this.itemValue);
},
methodChange(itemFunc, func) {
let index = this.mockVariableFuncs.indexOf(itemFunc);
this.mockVariableFuncs = this.mockVariableFuncs.slice(0, index);
// deep copy
this.mockVariableFuncs.push(JSON.parse(JSON.stringify(func)));
this.showPreview();
},
addFunc() {
if (this.mockVariableFuncs.length > 4) {
this.$info(this.$t('api_test.request.parameters_advance_add_func_limit'));
return;
}
if (this.mockVariableFuncs.length > 0) {
let func = this.mockVariableFuncs[this.mockVariableFuncs.length - 1];
if (!func.name) {
this.$warning(this.$t('api_test.request.parameters_advance_add_func_error'));
return;
}
if (func.params) {
for (let j = 0; j < func.params.length; j++) {
if (!func.params[j].value) {
this.$warning(this.$t('api_test.request.parameters_advance_add_param_error'));
return;
}
}
}
}
this.mockVariableFuncs.push({name: '', params: []});
},
saveAdvanced() {
this.currentItem.value = this.itemValue;
this.itemValueVisible = false;
this.mockVariableFuncs = [];
}
}
}
</script>
<style scoped>
.col-height {
height: 40vh;
overflow: auto;
}
</style>

View File

@ -0,0 +1,88 @@
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<el-tabs v-model="activeName">
<!-- 认证-->
<el-tab-pane :label="$t('api_test.delimit.request.verified')" name="verified">
<el-form :model="authConfig" size="small" :rules="rule"
ref="authConfig">
<el-form-item :label="$t('api_test.delimit.request.verification_method')" prop="verification">
<el-select v-model="authConfig.verification"
:placeholder="$t('api_test.delimit.request.verification_method')" filterable size="small">
<el-option
v-for="item in options"
:key="item.name"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('api_test.request.tcp.username')" prop="username"
v-if="authConfig.verification !='No Auth'">
<el-input :placeholder="$t('api_test.request.tcp.username')" v-model="authConfig.username"
class="ms-http-input" size="small">
</el-input>
</el-form-item>
<el-form-item :label="$t('commons.password')" prop="password" v-if="authConfig.verification !='No Auth'">
<el-input v-model="authConfig.password" :placeholder="$t('commons.password')" show-password autocomplete="off"
maxlength="20" show-word-limit/>
</el-form-item>
</el-form>
</el-tab-pane>
<!--加密-->
<el-tab-pane :label="$t('api_test.delimit.request.encryption')" name="encryption">
<el-form :model="authConfig" size="small" :rules="rule"
ref="authConfig">
<el-form-item :label="$t('api_test.delimit.request.encryption')" prop="encryption">
<el-select v-model="authConfig.isEncrypt"
:placeholder="$t('api_test.delimit.request.verification_method')" filterable size="small">
<el-option
v-for="item in encryptOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
</template>
<script>
import {HttpRequest} from "../../model/ScenarioModel";
export default {
name: "MsApiAuthConfig",
components: {},
props: {
authConfig: {},
request: HttpRequest,
},
data() {
return {
options: [{name: "No Auth"}, {name: "Basic Auth"}],
encryptOptions: [{id: false, name: "不加密"}],
activeName: "verified",
rule: {},
}
},
methods: {}
}
</script>
<style scoped>
</style>

View File

@ -1,27 +1,38 @@
<template>
<el-dialog :close-on-click-modal="false" :title="$t('api_test.delimit.request.title')" :visible.sync="httpVisible"
width="35%"
@closed="closeApi"
width="45%"
:destroy-on-close="true">
<el-form :model="httpForm" label-position="right" label-width="120px" size="small" :rules="rule" ref="httpForm">
<el-form :model="httpForm" label-position="right" label-width="80px" size="small" :rules="rule" ref="httpForm">
<el-form-item :label="$t('commons.name')" prop="name">
<el-input v-model="httpForm.name" autocomplete="off" :placeholder="$t('commons.name')"/>
</el-form-item>
<el-form-item :label="$t('api_report.request')" prop="request">
<el-select v-model="value" style="width: 20%">
<el-option v-for="item in options" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
<el-input style="margin-left:10px;width: 76%" v-model="httpForm.request" autocomplete="off"
:placeholder="$t('api_test.delimit.request.path_info')"/>
<el-form-item :label="$t('api_report.request')" prop="url">
<el-input :placeholder="$t('api_test.delimit.request.path_info')" v-model="httpForm.url"
class="ms-http-input" size="small">
<el-select v-model="value" slot="prepend" style="width: 100px" size="small">
<el-option v-for="item in options" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-input>
</el-form-item>
<el-form-item :label="$t('api_test.delimit.request.responsible')" prop="responsible">
<el-input v-model="httpForm.responsible" autocomplete="off"
:placeholder="$t('api_test.delimit.request.responsible')"/>
<el-form-item :label="$t('api_test.delimit.request.responsible')" prop="userId">
<el-select v-model="httpForm.userId"
:placeholder="$t('api_test.delimit.request.responsible')" filterable size="small"
style="width: 100%">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description" style="margin-bottom: 29px">
<el-input v-model="httpForm.description"
:placeholder="$t('commons.description')"/>
<el-input class="ms-http-textarea" v-model="httpForm.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
</el-form>
@ -36,6 +47,8 @@
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {TokenKey, WORKSPACE_ID} from '../../../../../../common/js/constants';
import {Scenario, KeyValue, Test} from "../../model/ScenarioModel"
export default {
name: "MsAddBasisHttpApi",
@ -45,8 +58,19 @@
return {
httpForm: {},
httpVisible: false,
rule: {},
value: "",
currentModule: {},
projectId: "",
maintainerOptions: [],
test: new Test(),
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
],
url: [{required: true, message: this.$t('api_test.delimit.request.path_info'), trigger: 'blur'}],
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
},
value: "GET",
options: [{
id: 'GET',
label: 'GET'
@ -61,14 +85,84 @@
},
methods: {
saveApi() {
this.$refs['httpForm'].validate((valid) => {
if (valid) {
let bodyFiles = [];
let url = "/api/delimit/create";
this.test.name = this.httpForm.name;
this.test.path = this.value;
this.test.url = this.httpForm.url;
this.test.userId = this.httpForm.userId;
this.test.description = this.httpForm.description;
this.test.request.url = this.httpForm.url;
this.test.request.path = this.value;
this.test.bodyUploadIds = [];
},
closeApi() {
this.test.projectId = this.projectId;
if (this.currentModule != null) {
this.test.modulePath = this.currentModule.path != undefined ? this.currentModule.path : null;
this.test.moduleId = this.currentModule.id;
}
let jmx = this.test.toJMX();
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
let file = new File([blob], jmx.name);
this.result = this.$fileUpload(url, file, bodyFiles, this.test, () => {
this.httpVisible = false;
this.$parent.refresh(this.currentModule);
});
} else {
return false;
}
})
},
open() {
urlChange() {
if (!this.httpForm.url) return;
let url = this.getURL(this.addProtocol(this.httpForm.url));
if (url) {
this.httpForm.url = decodeURIComponent(url.origin + url.pathname);
}
}
,
getURL(urlStr) {
try {
let url = new URL(urlStr);
url.searchParams.forEach((value, key) => {
if (key && value) {
this.request.parameters.splice(0, 0, new KeyValue({name: key, value: value}));
}
});
return url;
} catch (e) {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
}
,
addProtocol(url) {
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
}
}
return url;
},
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.maintainerOptions = response.data;
});
}
,
open(currentModule, projectId) {
this.httpForm = {};
this.test = new Test();
this.currentModule = currentModule;
this.projectId = projectId;
this.getMaintainerOptions();
this.httpVisible = true;
},
}
,
}
}
</script>

View File

@ -2,10 +2,17 @@
<div>
<el-radio-group v-model="body.type" size="mini">
<el-radio-button :disabled="isReadOnly" :label="type.KV">
{{ $t('api_test.request.body_kv') }}
{{ $t('api_test.delimit.request.body_form_data') }}
</el-radio-button>
<el-radio-button :disabled="isReadOnly" :label="type.RAW">
{{ $t('api_test.request.body_text') }}
{{ $t('api_test.delimit.request.body_raw') }}
</el-radio-button>
<el-radio-button :disabled="isReadOnly" :label="type.WWW_FORM">
{{ $t('api_test.delimit.request.body_x_www_from_urlencoded') }}
</el-radio-button>
<el-radio-button :disabled="isReadOnly" :label="type.BINARY">
{{ $t('api_test.delimit.request.body_binary') }}
</el-radio-button>
</el-radio-group>
@ -19,80 +26,98 @@
type="body"
:description="$t('api_test.request.parameters_desc')"
v-if="body.isKV()"/>
<ms-api-variable :is-read-only="isReadOnly"
:parameters="body.kvs"
:environment="environment"
:scenario="scenario"
:extract="extract"
type="body"
:description="$t('api_test.request.parameters_desc')"
v-if="body.type == 'WWW_Form'"/>
<ms-api-variable :is-read-only="isReadOnly"
:parameters="body.kvs"
:environment="environment"
:scenario="scenario"
:extract="extract"
type="body"
:description="$t('api_test.request.parameters_desc')"
v-if="body.type == 'BINARY'"/>
<div class="body-raw" v-if="body.type == 'Raw'">
<ms-code-edit :mode="body.format" :read-only="isReadOnly" :data.sync="body.raw" :modes="modes" ref="codeEdit"/>
</div>
</div>
</template>
<script>
import MsApiKeyValue from "../ApiKeyValue";
import {Body, BODY_FORMAT, BODY_TYPE, Scenario} from "../../model/ScenarioModel";
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
import MsDropdown from "../../../../common/components/MsDropdown";
import MsApiVariable from "../ApiVariable";
import MsApiKeyValue from "../ApiKeyValue";
import {Body, BODY_FORMAT, BODY_TYPE, Scenario} from "../../model/ScenarioModel";
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
import MsDropdown from "../../../../common/components/MsDropdown";
import MsApiVariable from "../ApiVariable";
export default {
name: "MsApiBody",
components: {MsApiVariable, MsDropdown, MsCodeEdit, MsApiKeyValue},
props: {
body: Body,
scenario: Scenario,
environment: Object,
extract: Object,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
type: BODY_TYPE,
modes: ['text', 'json', 'xml', 'html']
};
},
methods: {
modeChange(mode) {
this.body.format = mode;
}
},
created() {
if (!this.body.type) {
this.body.type = BODY_TYPE.KV;
}
if (!this.body.format) {
this.body.format = BODY_FORMAT.TEXT;
}
this.body.kvs.forEach(param => {
if (!param.type) {
param.type = 'text';
export default {
name: "MsApiBody",
components: {MsApiVariable, MsDropdown, MsCodeEdit, MsApiKeyValue},
props: {
body: Body,
scenario: Scenario,
environment: Object,
extract: Object,
isReadOnly: {
type: Boolean,
default: false
}
});
},
data() {
return {
type: BODY_TYPE,
modes: ['text', 'json', 'xml', 'html']
};
},
methods: {
modeChange(mode) {
this.body.format = mode;
}
},
created() {
if (!this.body.type) {
this.body.type = BODY_TYPE.KV;
}
if (!this.body.format) {
this.body.format = BODY_FORMAT.TEXT;
}
this.body.kvs.forEach(param => {
if (!param.type) {
param.type = 'text';
}
});
}
}
}
</script>
<style scoped>
.textarea {
margin-top: 10px;
}
.textarea {
margin-top: 10px;
}
.body-raw {
padding: 15px 0;
height: 300px;
}
.body-raw {
padding: 15px 0;
height: 300px;
}
.el-dropdown {
margin-left: 20px;
line-height: 30px;
}
.el-dropdown {
margin-left: 20px;
line-height: 30px;
}
.ace_editor {
border-radius: 5px;
}
.ace_editor {
border-radius: 5px;
}
</style>

View File

@ -1,48 +1,59 @@
<template>
<div class="card-container">
<el-card class="card-content" v-loading="result.loading">
<el-card class="card-content" v-loading="httpForm.loading">
<el-form :model="httpForm" :rules="rule" ref="httpForm" :inline="true" :label-position="labelPosition">
<el-form :model="httpForm" :rules="rule" ref="httpForm" :inline="true" label-position="right">
<div style="float: right;margin-right: 20px">
<el-button type="primary" size="small">{{$t('commons.save')}}</el-button>
<el-button type="primary" size="small" @click="saveApi">{{$t('commons.save')}}</el-button>
<el-button type="primary" size="small" @click="runTest(httpForm)">{{$t('commons.test')}}</el-button>
</div>
<br/>
<div style="font-size: 16px;color: #333333">{{$t('test_track.plan_view.base_info')}}</div>
<br/>
<el-form-item :label="$t('commons.name')" prop="name">
<el-input class="ms-http-input" size="small"/>
<el-input class="ms-http-input" size="small" v-model="httpForm.name"/>
</el-form-item>
<el-form-item :label="$t('test_track.module.module')" prop="module">
<el-select class="ms-http-input" size="small" v-model="moduleValue">
<el-option v-for="item in options" :key="item.id" :label="item.label" :value="item.id"/>
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<el-select class="ms-http-input" size="small" v-model="httpForm.moduleId">
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('api_test.delimit.request.responsible')" prop="responsible">
<el-input class="ms-http-input" size="small"/>
</el-form-item>
<el-form-item :label="$t('commons.status')" prop="status">
<el-select class="ms-http-input" size="small" v-model="moduleValue">
<el-option v-for="item in options" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('api_report.request')" prop="responsible">
<el-input :placeholder="$t('api_test.delimit.request.path_info')" v-model="httpForm.request"
<el-form-item :label="$t('api_report.request')" prop="url">
<el-input :placeholder="$t('api_test.delimit.request.path_info')" v-model="httpForm.url"
class="ms-http-input" size="small" style="margin-top: 5px">
<el-select v-model="reqValue" slot="prepend" style="width: 100px" size="small">
<el-select v-model="httpForm.path" 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-form-item>
<el-form-item :label="$t('commons.status')" prop="status">
<el-select class="ms-http-input" size="small" v-model="httpForm.status">
<el-option v-for="item in options" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('api_test.delimit.request.responsible')" prop="userId">
<el-select v-model="httpForm.userId"
:placeholder="$t('api_test.delimit.request.responsible')" filterable size="small"
class="ms-http-input">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="httpForm.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
@ -52,10 +63,10 @@
<div style="font-size: 16px;color: #333333;padding-top: 30px">请求参数</div>
<br/>
<!-- HTTP 请求参数 -->
<ms-api-request-form :debug-report-id="debugReportId" :request="selected" :scenario="currentScenario"/>
<ms-api-request-form :debug-report-id="debugReportId" :request="this.test.request"/>
</el-form>
<div style="font-size: 16px;color: #333333 ;padding-top: 30px">响应内容</div>
<div style="font-size: 16px;color: #333333 ;padding-top: 30px">响应模版</div>
<br/>
<ms-response-text :response="responseData"></ms-response-text>
</el-card>
@ -64,25 +75,33 @@
<script>
import MsApiRequestForm from "../request/ApiRequestForm";
import {Request, Scenario} from "../../model/ScenarioModel";
import MsResponseText from "../../../report/components/ResponseText";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import {Scenario, KeyValue, Test} from "../../model/ScenarioModel"
export default {
name: "MsAddCompleteHttpApi",
components: {MsResponseText, MsApiRequestForm},
data() {
return {
result: {},
rule: {},
labelPosition: 'right',
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
],
url: [{required: true, message: this.$t('api_test.delimit.request.path_info'), trigger: 'blur'}],
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
},
httpForm: {},
options: [],
reqValue: '',
debugReportId: '',
maintainerOptions: [],
responseData: {},
currentScenario: Scenario,
selected: [Scenario, Request],
currentScenario: new Scenario(),
currentModule: {},
postUrl: "",
reqOptions: [{
id: 'GET',
label: 'GET'
@ -90,19 +109,74 @@
id: 'POST',
label: 'POST'
}],
moduleValue: '',
options: [{
id: 'Prepare',
label: '未开始'
}, {
id: 'Underway',
label: '进行中'
}, {
id: 'Completed',
label: '已完成'
}],
}
},
props: {httpData: {},},
props: {httpData: {}, moduleOptions: {}, currentProject: {}, test: {}},
methods: {
runTest(data) {
this.$emit('runTest', data);
},
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.maintainerOptions = response.data;
});
},
saveApi() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['httpForm'].validate((valid) => {
if (valid) {
this.test.name = this.httpForm.name;
this.test.path = this.httpForm.path;
this.test.url = this.httpForm.url;
this.test.userId = this.httpForm.userId;
this.test.description = this.httpForm.description;
this.test.status = this.httpForm.status;
this.test.moduleId = this.httpForm.moduleId;
this.test.projectId = this.currentProject.id;
this.test.modulePath = this.getPath(this.httpForm.moduleId);
this.test.bodyUploadIds = [];
this.test.request.url = this.httpForm.url;
this.test.request.path = this.httpForm.path;
console.log(this.httpForm)
this.$emit('saveApi', this.test);
}
else {
return false;
}
}
)
},
getPath(id) {
if (id === null) {
return null;
}
let path = this.moduleOptions.filter(function (item) {
return item.id === id ? item.path : "";
});
return path[0].path;
}
},
watch: {
httpData(v) {
this.httpForm = v;
}
created() {
this.getMaintainerOptions();
this.httpForm = this.httpData;
}
}
</script>

View File

@ -1,158 +1,166 @@
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<el-form :model="request" :rules="rules" ref="request" label-width="100px" :disabled="isReadOnly">
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('api_test.request.parameters')" name="parameters">
<!-- 请求头-->
<el-tab-pane :label="$t('api_test.request.headers')" name="headers">
<ms-api-key-value :is-read-only="isReadOnly" :isShowEnable="true" :suggestions="headerSuggestions"
:items="request.headers"/>
</el-tab-pane>
<!--query 参数-->
<el-tab-pane :label="$t('api_test.delimit.request.query_param')" name="parameters">
<ms-api-variable :is-read-only="isReadOnly"
:parameters="request.parameters"
:environment="scenario.environment"
:scenario="scenario"
:environment="request.environment"
:extract="request.extract"
:description="$t('api_test.request.parameters_desc')"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.headers')" name="headers">
<ms-api-key-value :is-read-only="isReadOnly" :isShowEnable="true" :suggestions="headerSuggestions" :items="request.headers"/>
<!--REST 参数-->
<el-tab-pane :label="$t('api_test.delimit.request.rest_param')" name="rest">
<ms-api-key-value :is-read-only="isReadOnly" :isShowEnable="true" :suggestions="headerSuggestions"
:items="request.rest"/>
</el-tab-pane>
<!--请求体-->
<el-tab-pane :label="$t('api_test.request.body')" name="body">
<ms-api-body :is-read-only="isReadOnly"
:body="request.body"
:scenario="scenario"
:extract="request.extract"
:environment="scenario.environment"/>
:environment="request.environment"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
<ms-api-assertions :request="request" :is-read-only="isReadOnly" :assertions="request.assertions"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.extract.label')" name="extract">
<ms-api-extract :is-read-only="isReadOnly" :extract="request.extract"/>
<!-- 认证配置 -->
<el-tab-pane :label="$t('api_test.delimit.request.auth_config')" name="authConfig">
<ms-api-auth-config :request="request" :is-read-only="isReadOnly" :auth-config="request.authConfig"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.processor.pre_exec_script')" name="jsr223PreProcessor">
<ms-jsr233-processor :is-read-only="isReadOnly" :jsr223-processor="request.jsr223PreProcessor"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.processor.post_exec_script')" name="jsr223PostProcessor">
<ms-jsr233-processor :is-read-only="isReadOnly" :jsr223-processor="request.jsr223PostProcessor"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.timeout_config')" name="advancedConfig">
<ms-api-advanced-config :is-read-only="isReadOnly" :request="request"/>
</el-tab-pane>
</el-tabs>
</el-form>
</template>
<script>
import MsApiKeyValue from "../ApiKeyValue";
import MsApiBody from "../body/ApiBody";
import MsApiAssertions from "../assertion/ApiAssertions";
import {HttpRequest, KeyValue, Scenario} from "../../model/ScenarioModel";
import MsApiExtract from "../extract/ApiExtract";
import ApiRequestMethodSelect from "../collapse/ApiRequestMethodSelect";
import {REQUEST_HEADERS} from "@/common/js/constants";
import MsApiVariable from "../ApiVariable";
import MsJsr233Processor from "../processor/Jsr233Processor";
import MsApiAdvancedConfig from "../ApiAdvancedConfig";
import MsApiKeyValue from "../ApiKeyValue";
import MsApiBody from "../body/ApiBody";
import MsApiAuthConfig from "../auth/ApiAuthConfig";
import {HttpRequest, KeyValue, Scenario} from "../../model/ScenarioModel";
import MsApiExtract from "../extract/ApiExtract";
import ApiRequestMethodSelect from "../collapse/ApiRequestMethodSelect";
import {REQUEST_HEADERS} from "@/common/js/constants";
import MsApiVariable from "../ApiVariable";
import MsJsr233Processor from "../processor/Jsr233Processor";
import MsApiAdvancedConfig from "../ApiAdvancedConfig";
export default {
name: "MsApiHttpRequestForm",
components: {
MsJsr233Processor,
MsApiAdvancedConfig,
MsApiVariable, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiBody, MsApiKeyValue},
props: {
request: HttpRequest,
jsonPathList: Array,
scenario: Scenario,
isReadOnly: {
type: Boolean,
default: false
}
},
export default {
name: "MsApiHttpRequestForm",
components: {
MsJsr233Processor,
MsApiAdvancedConfig,
MsApiVariable, ApiRequestMethodSelect, MsApiExtract, MsApiAuthConfig, MsApiBody, MsApiKeyValue
},
props: {
request: HttpRequest,
jsonPathList: Array,
scenario: Scenario,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
let validateURL = (rule, value, callback) => {
try {
new URL(this.addProtocol(this.request.url));
} catch (e) {
callback(this.$t('api_test.request.url_invalid'));
}
};
return {
activeName: "parameters",
rules: {
name: [
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
],
url: [
{max: 500, required: true, message: this.$t('commons.input_limit', [1, 500]), trigger: 'blur'},
{validator: validateURL, trigger: 'blur'}
],
path: [
{max: 500, message: this.$t('commons.input_limit', [0, 500]), trigger: 'blur'},
]
},
headerSuggestions: REQUEST_HEADERS
}
},
methods: {
urlChange() {
if (!this.request.url) return;
let url = this.getURL(this.addProtocol(this.request.url));
if (url) {
this.request.url = decodeURIComponent(url.origin + url.pathname);
}
},
pathChange() {
if (!this.request.path) return;
let url = this.getURL(this.displayUrl);
let urlStr = url.origin + url.pathname;
let envUrl = this.scenario.environment.config.httpConfig.protocol + '://' + this.scenario.environment.config.httpConfig.socket;
this.request.path = decodeURIComponent(urlStr.substring(envUrl.length, urlStr.length));
},
getURL(urlStr) {
try {
let url = new URL(urlStr);
url.searchParams.forEach((value, key) => {
if (key && value) {
this.request.parameters.splice(0, 0, new KeyValue({name: key, value: value}));
}
});
return url;
} catch (e) {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
methodChange(value) {
if (value === 'GET' && this.activeName === 'body') {
this.activeName = 'parameters';
}
},
useEnvironmentChange(value) {
if (value && !this.scenario.environment) {
this.$error(this.$t('api_test.request.please_add_environment_to_scenario'), 2000);
this.request.useEnvironment = false;
}
this.$refs["request"].clearValidate();
},
addProtocol(url) {
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
data() {
let validateURL = (rule, value, callback) => {
try {
new URL(this.addProtocol(this.request.url));
} catch (e) {
callback(this.$t('api_test.request.url_invalid'));
}
};
return {
activeName: "headers",
rules: {
name: [
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
],
url: [
{max: 500, required: true, message: this.$t('commons.input_limit', [1, 500]), trigger: 'blur'},
{validator: validateURL, trigger: 'blur'}
],
path: [
{max: 500, message: this.$t('commons.input_limit', [0, 500]), trigger: 'blur'},
]
},
headerSuggestions: REQUEST_HEADERS
}
return url;
},
runDebug() {
this.$emit('runDebug');
}
},
computed: {
displayUrl() {
return (this.scenario.environment && this.scenario.environment.config.httpConfig.socket) ?
this.scenario.environment.config.httpConfig.protocol + '://' + this.scenario.environment.config.httpConfig.socket + (this.request.path ? this.request.path : '')
: '';
methods: {
urlChange() {
if (!this.request.url) return;
let url = this.getURL(this.addProtocol(this.request.url));
if (url) {
this.request.url = decodeURIComponent(url.origin + url.pathname);
}
},
pathChange() {
if (!this.request.path) return;
let url = this.getURL(this.displayUrl);
let urlStr = url.origin + url.pathname;
let envUrl = this.scenario.environment.config.httpConfig.protocol + '://' + this.scenario.environment.config.httpConfig.socket;
this.request.path = decodeURIComponent(urlStr.substring(envUrl.length, urlStr.length));
},
getURL(urlStr) {
try {
let url = new URL(urlStr);
url.searchParams.forEach((value, key) => {
if (key && value) {
this.request.parameters.splice(0, 0, new KeyValue({name: key, value: value}));
}
});
return url;
} catch (e) {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
methodChange(value) {
if (value === 'GET' && this.activeName === 'body') {
this.activeName = 'parameters';
}
},
useEnvironmentChange(value) {
if (value && !this.scenario.environment) {
this.$error(this.$t('api_test.request.please_add_environment_to_scenario'), 2000);
this.request.useEnvironment = false;
}
this.$refs["request"].clearValidate();
},
addProtocol(url) {
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
}
}
return url;
},
runDebug() {
this.$emit('runDebug');
}
},
computed: {
displayUrl() {
return (this.scenario.environment && this.scenario.environment.config.httpConfig.socket) ?
this.scenario.environment.config.httpConfig.protocol + '://' + this.scenario.environment.config.httpConfig.socket + (this.request.path ? this.request.path : '')
: '';
}
}
}
}
</script>
<style scoped>

View File

@ -2,13 +2,15 @@
<div class="request-form">
<component @runDebug="runDebug" :is="component" :is-read-only="isReadOnly" :request="request" :scenario="scenario"/>
<el-divider v-if="isCompleted"></el-divider>
<ms-request-result-tail v-loading="debugReportLoading" v-if="isCompleted" :request="request.debugRequestResult ? request.debugRequestResult : {responseResult: {}, subRequestResults: []}"
:scenario-name="request.debugScenario ? request.debugScenario.name : ''" ref="msDebugResult"/>
<ms-request-result-tail v-loading="debugReportLoading" v-if="isCompleted"
:request="request.debugRequestResult ? request.debugRequestResult : {responseResult: {}, subRequestResults: []}"
:scenario-name="request.debugScenario ? request.debugScenario.name : ''"
ref="msDebugResult"/>
</div>
</template>
<script>
import {JSR223Processor, Request, RequestFactory, Scenario} from "../../model/ScenarioModel";
import {JSR223Processor, Request, RequestFactory, Scenario, Test} from "../../model/ScenarioModel";
import MsApiHttpRequestForm from "./ApiHttpRequestForm";
// import MsApiTcpRequestForm from "./ApiTcpRequestForm";
// import MsApiDubboRequestForm from "./ApiDubboRequestForm";
@ -16,25 +18,25 @@
import MsRequestResultTail from "../../../report/components/RequestResultTail";
// import MsApiSqlRequestForm from "./ApiSqlRequestForm";
export default {
name: "MsApiRequestForm",
components: { MsRequestResultTail, MsScenarioResults, MsApiHttpRequestForm},
props: {
scenario: Scenario,
request: Request,
isReadOnly: {
type: Boolean,
default: false
export default {
name: "MsApiRequestForm",
components: {MsRequestResultTail, MsScenarioResults, MsApiHttpRequestForm},
props: {
scenario: Scenario,
request: Request,
isReadOnly: {
type: Boolean,
default: false
},
debugReportId: String
},
debugReportId: String
},
data() {
return {
reportId: "",
content: {scenarios:[]},
content: {scenarios: []},
debugReportLoading: false,
showDebugReport: false,
jsonPathList:[]
jsonPathList: [],
}
},
computed: {
@ -47,9 +49,9 @@ export default {
case RequestFactory.TYPES.SQL:
name = "MsApiSqlRequestForm";
break;
case RequestFactory.TYPES.TCP:
name = "MsApiTcpRequestForm";
break;
case RequestFactory.TYPES.TCP:
name = "MsApiTcpRequestForm";
break;
default:
name = "MsApiHttpRequestForm";
}

View File

@ -80,7 +80,10 @@ export const calculate = function (itemValue) {
export const BODY_TYPE = {
KV: "KeyValue",
FORM_DATA: "Form Data",
RAW: "Raw"
RAW: "Raw",
WWW_FORM: "WWW_Form",
XML: "XML",
BINARY: "BINARY"
}
export const BODY_FORMAT = {
@ -118,7 +121,8 @@ export class BaseConfig {
if (!(this[name] instanceof Array)) {
if (notUndefined === true) {
this[name] = options[name] === undefined ? this[name] : options[name];
} else {
}
else {
this[name] = options[name];
}
}
@ -156,36 +160,18 @@ export class Test extends BaseConfig {
this.id = uuid();
this.name = undefined;
this.projectId = undefined;
this.scenarioDefinition = [];
this.request = {};
this.schedule = {};
this.set(options);
this.sets({scenarioDefinition: Scenario}, options);
}
export() {
let obj = {
type: this.type,
version: this.version,
scenarios: this.scenarioDefinition
};
return JSON.stringify(obj);
}
initOptions(options) {
options = options || {};
options.scenarioDefinition = options.scenarioDefinition || [new Scenario()];
options.request = options.request || new RequestFactory();
return options;
}
isValid() {
for (let i = 0; i < this.scenarioDefinition.length; i++) {
let validator = this.scenarioDefinition[i].isValid();
if (!validator.isValid) {
return validator;
}
}
if (!this.projectId) {
return {
isValid: false,
@ -224,7 +210,6 @@ export class Scenario extends BaseConfig {
this.enable = true;
this.databaseConfigs = [];
this.tcpConfig = undefined;
this.set(options);
this.sets({
variables: KeyValue,
@ -341,6 +326,8 @@ export class HttpRequest extends Request {
this.path = options.path;
this.method = options.method || "GET";
this.parameters = [];
this.rest = [];
this.authConfig = {verification: "No Auth", isEncrypt: false};
this.headers = [];
this.body = new Body(options.body);
this.environment = options.environment;
@ -351,7 +338,7 @@ export class HttpRequest extends Request {
this.responseTimeout = options.responseTimeout;
this.followRedirects = options.followRedirects === undefined ? true : options.followRedirects;
this.sets({parameters: KeyValue, headers: KeyValue}, options);
this.sets({parameters: KeyValue, rest: KeyValue, headers: KeyValue}, options);
}
isValid(environmentId, environment) {
@ -1015,7 +1002,7 @@ class JMXHttpRequest {
}
class JMXDubboRequest {
constructor(request, dubboConfig) {
constructor(request) {
// Request 复制
let obj = request.clone();
// 去掉无效的kv
@ -1025,12 +1012,6 @@ class JMXDubboRequest {
obj.attachmentArgs = obj.attachmentArgs.filter(arg => {
return arg.isValid();
});
// Scenario DubboConfig复制
this.copy(obj.configCenter, dubboConfig.configCenter);
this.copy(obj.registryCenter, dubboConfig.registryCenter);
this.copy(obj.consumerAndService, dubboConfig.consumerAndService);
return obj;
}
@ -1046,15 +1027,11 @@ class JMXDubboRequest {
}
class JMXTCPRequest {
constructor(request, scenario) {
constructor(request) {
let obj = request.clone();
if (request.useEnvironment) {
obj.set(scenario.environment.config.tcpConfig, true);
return obj;
}
this.copy(this, scenario.tcpConfig);
return obj;
}
@ -1090,70 +1067,51 @@ class JMXGenerator {
if (!test || !test.id || !(test instanceof Test)) return undefined;
let testPlan = new TestPlan(test.name);
this.addScenarios(testPlan, test.id, test.scenarioDefinition);
this.addScenarios(testPlan, test.id, test.request);
this.jmeterTestPlan = new JMeterTestPlan();
this.jmeterTestPlan.put(testPlan);
}
addScenarios(testPlan, testId, scenarios) {
scenarios.forEach(s => {
addScenarios(testPlan, testId, request) {
if (s.enable) {
let scenario = s.clone();
let threadGroup = new ThreadGroup(request.name || "");
let threadGroup = new ThreadGroup(scenario.name || "");
if (!request.isValid()) return;
let sampler;
if (request instanceof DubboRequest) {
sampler = new DubboSample(request.name || "", new JMXDubboRequest(request));
} else if (request instanceof HttpRequest) {
sampler = new HTTPSamplerProxy(request.name || "", new JMXHttpRequest(request, false));
this.addRequestHeader(sampler, request);
this.addRequestArguments(sampler, request);
this.addRequestBody(sampler, request, testId);
} else if (request instanceof SqlRequest) {
sampler = new JDBCSampler(request.name || "", request);
this.addRequestVariables(sampler, request);
} else if (request instanceof TCPRequest) {
sampler = new TCPSampler(request.name || "", new JMXTCPRequest(request));
}
this.addScenarioVariables(threadGroup, scenario);
this.addDNSCacheManager(sampler, false, request.useEnvironment);
this.addScenarioHeaders(threadGroup, scenario);
this.addRequestExtractor(sampler, request);
this.addScenarioCookieManager(threadGroup, scenario);
this.addRequestAssertion(sampler, request);
this.addJDBCDataSources(threadGroup, scenario);
scenario.requests.forEach(request => {
if (request.enable) {
if (!request.isValid()) return;
let sampler;
if (request instanceof DubboRequest) {
sampler = new DubboSample(request.name || "", new JMXDubboRequest(request, scenario.dubboConfig));
} else if (request instanceof HttpRequest) {
sampler = new HTTPSamplerProxy(request.name || "", new JMXHttpRequest(request, scenario.environment));
this.addRequestHeader(sampler, request);
this.addRequestArguments(sampler, request);
this.addRequestBody(sampler, request, testId);
} else if (request instanceof SqlRequest) {
request.dataSource = scenario.databaseConfigMap.get(request.dataSource);
sampler = new JDBCSampler(request.name || "", request);
this.addRequestVariables(sampler, request);
} else if (request instanceof TCPRequest) {
sampler = new TCPSampler(request.name || "", new JMXTCPRequest(request, scenario));
}
this.addJSR223PreProcessor(sampler, request);
this.addDNSCacheManager(sampler, scenario.environment, request.useEnvironment);
this.addConstantsTimer(sampler, request);
this.addRequestExtractor(sampler, request);
this.addRequestAssertion(sampler, request);
this.addJSR223PreProcessor(sampler, request);
this.addConstantsTimer(sampler, request);
if (request.controller && request.controller.isValid() && request.controller.enable) {
if (request.controller instanceof IfController) {
let controller = this.getController(sampler, request);
threadGroup.put(controller);
}
} else {
threadGroup.put(sampler);
}
}
})
testPlan.put(threadGroup);
if (request.controller && request.controller.isValid() && request.controller.enable) {
if (request.controller instanceof IfController) {
let controller = this.getController(sampler, request);
threadGroup.put(controller);
}
})
} else {
threadGroup.put(sampler);
}
testPlan.put(threadGroup);
}
addEnvironments(environments, target) {

View File

@ -1,10 +1,5 @@
<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">
<ms-sql-result-table v-if="isSqlType" :body="response.body"/>
@ -28,7 +23,6 @@
</el-tab-pane>
</el-tabs>
</el-collapse-transition>
</div>
</template>

View File

@ -228,7 +228,7 @@ export default {
mail: 'mail',
nail_robot: 'Nail robot',
enterprise_wechat_robot: 'Enterprise wechat robot',
notes:'Note: 1. Nail and create a custom robot in the enterprise group, and then copy the webhook address on our platform;\n' +
notes: 'Note: 1. Nail and create a custom robot in the enterprise group, and then copy the webhook address on our platform;\n' +
'\n' +
'2. Robots are selected as swarm robots, and "custom keyword" is selected for security verification: "task notification";\n' +
'\n' +
@ -471,14 +471,25 @@ export default {
select_case: "Search use cases",
case: "Case",
title: "Create api",
path_info:"Please enter the URL of the interface, such as /api/demo/#{id}, where id is the path parameter",
path_info: "Please enter the URL of the interface, such as /api/demo/#{id}, where id is the path parameter",
fast_debug: "Fast debug",
close_all_label: "close all label",
save_as: "Save as new interface",
load_case: "Load use case",
save_as_case: "Save as new use case",
update_api: "Update interface",
body_form_data: "form-data",
body_x_www_from_urlencoded: "x-www-from-urlencoded",
body_raw: "raw",
body_binary: "binary",
body_json: "json",
body_xml: "xml",
auth_config: "Authentication configuration",
rest_param: "Rest parameter",
query_param: "Query parameter",
verification_method: "Verification method",
verified: "verified",
encryption: "encryption",
}
},
environment: {

View File

@ -229,7 +229,7 @@ export default {
mail: '邮件',
nail_robot: '钉钉机器人',
enterprise_wechat_robot: '企业微信机器人',
notes:'注意:1.钉钉和企业群里新建一个自定义机器人,然后复制 webhook 地址在我们平台上;\n' +
notes: '注意:1.钉钉和企业群里新建一个自定义机器人,然后复制 webhook 地址在我们平台上;\n' +
' 2.机器人选择为群机器人,安全验证选择“自定义关键词” "任务通知";\n' +
' 3.选择接收人时必须是你所建的群里包含的人,接收人手机号为必填项且为钉钉企业所使用的手机号,',
message: '事件,接收人,接收方式为必填项',
@ -479,6 +479,19 @@ export default {
load_case: "加载用例",
save_as_case: "另存为新用例",
update_api: "更新接口",
body_form_data: "form-data",
body_x_www_from_urlencoded: "x-www-from-urlencoded",
body_raw: "raw",
body_binary: "binary",
body_json: "json",
body_xml: "xml",
auth_config: "认证配置",
rest_param: "REST参数",
query_param: "QUERY参数",
verification_method: "认证方式",
verified: "认证",
encryption: "加密",
}
},
environment: {

View File

@ -472,14 +472,25 @@ export default {
case: "用例",
responsible: "责任人",
title: "创建接口",
path_info:"請輸入接口的URL如/api/demo/#{id}其中id為路徑參數",
path_info: "請輸入接口的URL如/api/demo/#{id}其中id為路徑參數",
fast_debug: "快捷調試",
close_all_label: "關閉所有標簽",
save_as: "另存為新接口",
load_case: "加载用例",
save_as_case: "另存為新用例",
update_api: "更新接口",
body_form_data: "form-data",
body_x_www_from_urlencoded: "x-www-from-urlencoded",
body_raw: "raw",
body_binary: "binary",
body_json: "json",
body_xml: "xml",
auth_config: "認證配置",
rest_param: "REST參數",
query_param: "QUERY參數",
verification_method: "認證方式",
verified: "認證",
encryption: "加密",
}
},