提交 b8488309 编写于 作者: F fit2-zhao

feat(接口自动化): 完成场景批量执行,基础报告生成

上级 1aab595a
package io.metersphere.api.controller; package io.metersphere.api.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.APIReportResult; import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.DeleteAPIReportRequest;
import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.service.ApiScenarioReportService; import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.commons.constants.RoleConstants; 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.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
@RestController @RestController
@RequestMapping(value = "/api/scenario/report") @RequestMapping(value = "/api/scenario/report")
...@@ -20,8 +26,41 @@ public class APIScenarioReportController { ...@@ -20,8 +26,41 @@ public class APIScenarioReportController {
@Resource @Resource
private ApiScenarioReportService apiReportService; private ApiScenarioReportService apiReportService;
@GetMapping("/get/{reportId}") @GetMapping("/get/{reportId}/{infoDb}")
public APIReportResult get(@PathVariable String reportId) { public APIReportResult get(@PathVariable String reportId,@PathVariable Boolean infoDb) {
if(infoDb){
return apiReportService.get(reportId);
}
return apiReportService.getCacheResult(reportId); return apiReportService.getCacheResult(reportId);
} }
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<APIScenarioReportResult>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryAPIReportRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return PageUtils.setPageInfo(page, apiReportService.list(request));
}
@PostMapping("/add")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public String add(@RequestBody APIScenarioReportResult node) {
return apiReportService.add(node);
}
@PostMapping("/update")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public String update(@RequestBody APIScenarioReportResult node) {
return apiReportService.update(node);
}
@PostMapping("/delete")
public void delete(@RequestBody DeleteAPIReportRequest request) {
apiReportService.delete(request);
}
@PostMapping("/batch/delete")
public void deleteAPIReportBatch(@RequestBody DeleteAPIReportRequest reportRequest) {
apiReportService.deleteAPIReportBatch(reportRequest);
}
} }
...@@ -4,6 +4,7 @@ import com.github.pagehelper.Page; ...@@ -4,6 +4,7 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.automation.ApiScenarioDTO; import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest; import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.dto.automation.SaveApiScenarioRequest; import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
import io.metersphere.api.dto.definition.RunDefinitionRequest; import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.service.ApiAutomationService; import io.metersphere.api.service.ApiAutomationService;
...@@ -36,13 +37,13 @@ public class ApiAutomationController { ...@@ -36,13 +37,13 @@ public class ApiAutomationController {
} }
@PostMapping(value = "/create") @PostMapping(value = "/create")
public void create(@RequestBody SaveApiScenarioRequest request) { public void create(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiAutomationService.create(request); apiAutomationService.create(request, bodyFiles);
} }
@PostMapping(value = "/update") @PostMapping(value = "/update")
public void update(@RequestBody SaveApiScenarioRequest request) { public void update(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiAutomationService.update(request); apiAutomationService.update(request, bodyFiles);
} }
@GetMapping("/delete/{id}") @GetMapping("/delete/{id}")
...@@ -70,9 +71,15 @@ public class ApiAutomationController { ...@@ -70,9 +71,15 @@ public class ApiAutomationController {
return apiAutomationService.getApiScenarios(ids); return apiAutomationService.getApiScenarios(ids);
} }
@PostMapping(value = "/run") @PostMapping(value = "/run/debug")
public void runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) { public void runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiAutomationService.run(request, bodyFiles); apiAutomationService.run(request, bodyFiles);
} }
@PostMapping(value = "/run")
public void run(@RequestBody RunScenarioRequest request) {
apiAutomationService.run(request);
}
} }
package io.metersphere.api.dto.automation;
import io.metersphere.base.domain.ApiScenarioReport;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class APIScenarioReportResult extends ApiScenarioReport {
private String testName;
private String projectName;
private String userName;
private String content;
}
package io.metersphere.api.dto.automation;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class RunScenarioRequest {
private String id;
private String reportId;
private String environmentId;
private List<String> scenarioIds;
}
...@@ -3,6 +3,8 @@ package io.metersphere.api.dto.automation; ...@@ -3,6 +3,8 @@ package io.metersphere.api.dto.automation;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.List;
@Setter @Setter
@Getter @Getter
public class SaveApiScenarioRequest { public class SaveApiScenarioRequest {
...@@ -35,4 +37,6 @@ public class SaveApiScenarioRequest { ...@@ -35,4 +37,6 @@ public class SaveApiScenarioRequest {
private String description; private String description;
private String scenarioDefinition; private String scenarioDefinition;
List<String> bodyUploadIds;
} }
...@@ -4,6 +4,9 @@ import com.alibaba.fastjson.JSON; ...@@ -4,6 +4,9 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType; import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.service.ApiAutomationService; import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiTestEnvironmentService; import io.metersphere.api.service.ApiTestEnvironmentService;
...@@ -15,6 +18,7 @@ import lombok.EqualsAndHashCode; ...@@ -15,6 +18,7 @@ import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import java.util.LinkedList;
import java.util.List; import java.util.List;
@Data @Data
...@@ -41,14 +45,21 @@ public class MsScenario extends MsTestElement { ...@@ -41,14 +45,21 @@ public class MsScenario extends MsTestElement {
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) { if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
return; return;
} else if (this.getReferenced() != null && this.getReferenced().equals("REF")) { } else if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
ApiAutomationService apiAutomationService = CommonBeanFactory.getBean(ApiAutomationService.class); try {
ApiScenario scenario = apiAutomationService.getApiScenario(this.getId()); ApiAutomationService apiAutomationService = CommonBeanFactory.getBean(ApiAutomationService.class);
JSONObject element = JSON.parseObject(scenario.getScenarioDefinition()); ObjectMapper mapper = new ObjectMapper();
List<MsTestElement> dataArr = JSON.parseArray(element.getString("hashTree"), MsTestElement.class); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
if (hashTree == null) { ApiScenario scenario = apiAutomationService.getApiScenario(this.getId());
hashTree = dataArr; JSONObject element = JSON.parseObject(scenario.getScenarioDefinition());
} else { LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
hashTree.addAll(dataArr); });
if (hashTree == null) {
hashTree = elements;
} else {
hashTree.addAll(elements);
}
} catch (Exception ex) {
ex.printStackTrace();
} }
} }
if (CollectionUtils.isNotEmpty(hashTree)) { if (CollectionUtils.isNotEmpty(hashTree)) {
......
...@@ -51,7 +51,7 @@ import java.util.List; ...@@ -51,7 +51,7 @@ import java.util.List;
MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class, MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class,
MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class}, typeKey = "type") MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class}, typeKey = "type")
@Data @Data
public abstract class MsTestElement { public class MsTestElement {
private String type; private String type;
@JSONField(ordinal = 1) @JSONField(ordinal = 1)
private String id; private String id;
......
...@@ -50,4 +50,5 @@ public class MsThreadGroup extends MsTestElement { ...@@ -50,4 +50,5 @@ public class MsThreadGroup extends MsTestElement {
threadGroup.setSamplerController(loopController); threadGroup.setSamplerController(loopController);
return threadGroup; return threadGroup;
} }
} }
...@@ -169,7 +169,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl ...@@ -169,7 +169,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
} }
} else if (StringUtils.equals(this.runMode, ApiRunMode.SCENARIO.name())) { } else if (StringUtils.equals(this.runMode, ApiRunMode.SCENARIO.name())) {
// 执行报告不需要存储,由用户确认后在存储 // 执行报告不需要存储,由用户确认后在存储
testResult.setTestId(debugReportId); testResult.setTestId(testId);
apiScenarioReportService.complete(testResult); apiScenarioReportService.complete(testResult);
} else { } else {
apiTestService.changeStatus(testId, APITestStatus.Completed); apiTestService.changeStatus(testId, APITestStatus.Completed);
......
...@@ -2,13 +2,16 @@ package io.metersphere.api.service; ...@@ -2,13 +2,16 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson; import com.google.gson.Gson;
import io.metersphere.api.dto.APIReportResult; import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.automation.ApiScenarioDTO; import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
import io.metersphere.api.dto.automation.ScenarioStatus;
import io.metersphere.api.dto.definition.RunDefinitionRequest; import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
...@@ -24,6 +27,7 @@ import io.metersphere.i18n.Translator; ...@@ -24,6 +27,7 @@ import io.metersphere.i18n.Translator;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import org.aspectj.util.FileUtil; import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
...@@ -32,9 +36,9 @@ import org.springframework.web.multipart.MultipartFile; ...@@ -32,9 +36,9 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
...@@ -83,8 +87,9 @@ public class ApiAutomationService { ...@@ -83,8 +87,9 @@ public class ApiAutomationService {
apiScenarioMapper.deleteByExample(example); apiScenarioMapper.deleteByExample(example);
} }
public void create(SaveApiScenarioRequest request) { public void create(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles) {
checkNameExist(request); checkNameExist(request);
final ApiScenario scenario = new ApiScenario(); final ApiScenario scenario = new ApiScenario();
scenario.setId(request.getId()); scenario.setId(request.getId());
scenario.setName(request.getName()); scenario.setName(request.getName());
...@@ -111,10 +116,16 @@ public class ApiAutomationService { ...@@ -111,10 +116,16 @@ public class ApiAutomationService {
} }
scenario.setDescription(request.getDescription()); scenario.setDescription(request.getDescription());
apiScenarioMapper.insert(scenario); apiScenarioMapper.insert(scenario);
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(bodyUploadIds, bodyFiles);
} }
public void update(SaveApiScenarioRequest request) { public void update(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles) {
checkNameExist(request); checkNameExist(request);
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(bodyUploadIds, bodyFiles);
final ApiScenario scenario = new ApiScenario(); final ApiScenario scenario = new ApiScenario();
scenario.setId(request.getId()); scenario.setId(request.getId());
scenario.setName(request.getName()); scenario.setName(request.getName());
...@@ -176,7 +187,7 @@ public class ApiAutomationService { ...@@ -176,7 +187,7 @@ public class ApiAutomationService {
} }
private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) { private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (!bodyUploadIds.isEmpty()) { if (!bodyUploadIds.isEmpty() && !bodyFiles.isEmpty()) {
File testDir = new File(BODY_FILE_DIR); File testDir = new File(BODY_FILE_DIR);
if (!testDir.exists()) { if (!testDir.exists()) {
testDir.mkdirs(); testDir.mkdirs();
...@@ -208,6 +219,63 @@ public class ApiAutomationService { ...@@ -208,6 +219,63 @@ public class ApiAutomationService {
} }
} }
private void createAPIReportResult(String id) {
APIReportResult report = new APIReportResult();
report.setId(id);
report.setTestId(id);
report.setName("");
report.setTriggerMode(null);
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
report.setStatus(APITestStatus.Running.name());
report.setUserId(SessionUtils.getUserId());
apiReportService.addResult(report);
}
/**
* 场景测试执行
*
* @param request
* @return
*/
public String run(RunScenarioRequest request) {
List<ApiScenario> apiScenarios = extApiScenarioMapper.selectIds(request.getScenarioIds());
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
HashTree jmeterTestPlanHashTree = new ListedHashTree();
EnvironmentConfig config = null;
for (ApiScenario item : apiScenarios) {
MsThreadGroup group = new MsThreadGroup();
group.setLabel(item.getName());
group.setName(item.getName());
try {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JSONObject element = JSON.parseObject(item.getScenarioDefinition());
String environmentId = element.getString("environmentId");
if (environmentId != null) {
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
}
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
group.setHashTree(elements);
testPlan.getHashTree().add(group);
} catch (Exception ex) {
ex.printStackTrace();
}
}
testPlan.toHashTree(jmeterTestPlanHashTree, testPlan.getHashTree(), config);
// 调用执行方法
jMeterService.runDefinition(request.getId(), jmeterTestPlanHashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
createAPIReportResult(request.getId());
return request.getId();
}
/** /**
* 场景测试执行 * 场景测试执行
* *
...@@ -228,17 +296,7 @@ public class ApiAutomationService { ...@@ -228,17 +296,7 @@ public class ApiAutomationService {
// 调用执行方法 // 调用执行方法
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.SCENARIO.name()); jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
APIReportResult report = new APIReportResult(); createAPIReportResult(request.getId());
report.setId(UUID.randomUUID().toString());
report.setTestId(request.getReportId());
report.setName("RUN");
report.setTriggerMode(null);
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
report.setStatus(APITestStatus.Running.name());
report.setUserId(SessionUtils.getUserId());
apiReportService.addResult(report);
return request.getId(); return request.getId();
} }
} }
...@@ -2,23 +2,39 @@ package io.metersphere.api.service; ...@@ -2,23 +2,39 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.APIReportResult; import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.DeleteAPIReportRequest;
import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.jmeter.TestResult; import io.metersphere.api.jmeter.TestResult;
import io.metersphere.base.domain.ApiTestReportDetail; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioReportDetailMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper;
import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import sun.security.util.Cache; import sun.security.util.Cache;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class ApiScenarioReportService { public class ApiScenarioReportService {
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24); private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24);
@Resource
private ExtApiScenarioReportMapper extApiScenarioReportMapper;
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
private ApiScenarioReportDetailMapper apiScenarioReportDetailMapper;
public void complete(TestResult result) { public void complete(TestResult result) {
Object obj = cache.get(result.getTestId()); Object obj = cache.get(result.getTestId());
...@@ -64,4 +80,103 @@ public class ApiScenarioReportService { ...@@ -64,4 +80,103 @@ public class ApiScenarioReportService {
} }
return null; return null;
} }
public APIReportResult get(String reportId) {
APIReportResult reportResult = extApiScenarioReportMapper.get(reportId);
ApiScenarioReportDetail detail = apiScenarioReportDetailMapper.selectByPrimaryKey(reportId);
if (detail != null) {
reportResult.setContent(new String(detail.getContent(), StandardCharsets.UTF_8));
}
return reportResult;
}
public List<APIScenarioReportResult> list(QueryAPIReportRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
return extApiScenarioReportMapper.list(request);
}
private void checkNameExist(APIScenarioReportResult request) {
ApiScenarioReportExample example = new ApiScenarioReportExample();
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
if (apiScenarioReportMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("load_test_already_exists"));
}
}
public ApiScenarioReport createReport(APIScenarioReportResult test) {
checkNameExist(test);
ApiScenarioReport report = new ApiScenarioReport();
report.setId(UUID.randomUUID().toString());
report.setProjectId(test.getProjectId());
report.setName(test.getName());
report.setTriggerMode(test.getTriggerMode());
report.setDescription(test.getDescription());
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
report.setStatus(test.getStatus());
report.setUserId(test.getUserId());
apiScenarioReportMapper.insert(report);
return report;
}
public ApiScenarioReport updateReport(APIScenarioReportResult test) {
checkNameExist(test);
ApiScenarioReport report = new ApiScenarioReport();
report.setId(test.getId());
report.setProjectId(test.getProjectId());
report.setName(test.getName());
report.setTriggerMode(test.getTriggerMode());
report.setDescription(test.getDescription());
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
report.setStatus(test.getStatus());
report.setUserId(test.getUserId());
apiScenarioReportMapper.updateByPrimaryKey(report);
return report;
}
public String add(APIScenarioReportResult test) {
ApiScenarioReport report = createReport(test);
ApiScenarioReportDetail detail = new ApiScenarioReportDetail();
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
detail.setReportId(report.getId());
detail.setProjectId(test.getProjectId());
apiScenarioReportDetailMapper.insert(detail);
return report.getId();
}
public String update(APIScenarioReportResult test) {
ApiScenarioReport report = updateReport(test);
ApiScenarioReportDetail detail = apiScenarioReportDetailMapper.selectByPrimaryKey(test.getId());
if (detail == null) {
detail = new ApiScenarioReportDetail();
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
detail.setReportId(report.getId());
detail.setProjectId(test.getProjectId());
apiScenarioReportDetailMapper.insert(detail);
} else {
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
detail.setReportId(report.getId());
detail.setProjectId(test.getProjectId());
apiScenarioReportDetailMapper.updateByPrimaryKey(detail);
}
return report.getId();
}
public void delete(DeleteAPIReportRequest request) {
apiScenarioReportDetailMapper.deleteByPrimaryKey(request.getId());
apiScenarioReportMapper.deleteByPrimaryKey(request.getId());
}
public void deleteAPIReportBatch(DeleteAPIReportRequest reportRequest) {
ApiScenarioReportDetailExample detailExample = new ApiScenarioReportDetailExample();
detailExample.createCriteria().andReportIdIn(reportRequest.getIds());
apiScenarioReportDetailMapper.deleteByExample(detailExample);
ApiScenarioReportExample apiTestReportExample = new ApiScenarioReportExample();
apiTestReportExample.createCriteria().andIdIn(reportRequest.getIds());
apiScenarioReportMapper.deleteByExample(apiTestReportExample);
}
} }
package io.metersphere.base.domain; package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
@Data @Data
public class ApiScenarioReport implements Serializable { public class ApiScenarioReport implements Serializable {
private String id; private String id;
private String scenarioId; private String projectId;
private String name; private String name;
......
...@@ -7,7 +7,7 @@ import lombok.Data; ...@@ -7,7 +7,7 @@ import lombok.Data;
public class ApiScenarioReportDetail implements Serializable { public class ApiScenarioReportDetail implements Serializable {
private String reportId; private String reportId;
private String scenarioId; private String projectId;
private byte[] content; private byte[] content;
......
...@@ -174,73 +174,73 @@ public class ApiScenarioReportDetailExample { ...@@ -174,73 +174,73 @@ public class ApiScenarioReportDetailExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIsNull() { public Criteria andProjectIdIsNull() {
addCriterion("scenario_id is null"); addCriterion("project_id is null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIsNotNull() { public Criteria andProjectIdIsNotNull() {
addCriterion("scenario_id is not null"); addCriterion("project_id is not null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdEqualTo(String value) { public Criteria andProjectIdEqualTo(String value) {
addCriterion("scenario_id =", value, "scenarioId"); addCriterion("project_id =", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotEqualTo(String value) { public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("scenario_id <>", value, "scenarioId"); addCriterion("project_id <>", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdGreaterThan(String value) { public Criteria andProjectIdGreaterThan(String value) {
addCriterion("scenario_id >", value, "scenarioId"); addCriterion("project_id >", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdGreaterThanOrEqualTo(String value) { public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("scenario_id >=", value, "scenarioId"); addCriterion("project_id >=", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLessThan(String value) { public Criteria andProjectIdLessThan(String value) {
addCriterion("scenario_id <", value, "scenarioId"); addCriterion("project_id <", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLessThanOrEqualTo(String value) { public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("scenario_id <=", value, "scenarioId"); addCriterion("project_id <=", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLike(String value) { public Criteria andProjectIdLike(String value) {
addCriterion("scenario_id like", value, "scenarioId"); addCriterion("project_id like", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotLike(String value) { public Criteria andProjectIdNotLike(String value) {
addCriterion("scenario_id not like", value, "scenarioId"); addCriterion("project_id not like", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIn(List<String> values) { public Criteria andProjectIdIn(List<String> values) {
addCriterion("scenario_id in", values, "scenarioId"); addCriterion("project_id in", values, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotIn(List<String> values) { public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("scenario_id not in", values, "scenarioId"); addCriterion("project_id not in", values, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdBetween(String value1, String value2) { public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("scenario_id between", value1, value2, "scenarioId"); addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotBetween(String value1, String value2) { public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("scenario_id not between", value1, value2, "scenarioId"); addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this; return (Criteria) this;
} }
} }
......
...@@ -174,73 +174,73 @@ public class ApiScenarioReportExample { ...@@ -174,73 +174,73 @@ public class ApiScenarioReportExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIsNull() { public Criteria andProjectIdIsNull() {
addCriterion("scenario_id is null"); addCriterion("project_id is null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIsNotNull() { public Criteria andProjectIdIsNotNull() {
addCriterion("scenario_id is not null"); addCriterion("project_id is not null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdEqualTo(String value) { public Criteria andProjectIdEqualTo(String value) {
addCriterion("scenario_id =", value, "scenarioId"); addCriterion("project_id =", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotEqualTo(String value) { public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("scenario_id <>", value, "scenarioId"); addCriterion("project_id <>", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdGreaterThan(String value) { public Criteria andProjectIdGreaterThan(String value) {
addCriterion("scenario_id >", value, "scenarioId"); addCriterion("project_id >", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdGreaterThanOrEqualTo(String value) { public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("scenario_id >=", value, "scenarioId"); addCriterion("project_id >=", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLessThan(String value) { public Criteria andProjectIdLessThan(String value) {
addCriterion("scenario_id <", value, "scenarioId"); addCriterion("project_id <", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLessThanOrEqualTo(String value) { public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("scenario_id <=", value, "scenarioId"); addCriterion("project_id <=", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLike(String value) { public Criteria andProjectIdLike(String value) {
addCriterion("scenario_id like", value, "scenarioId"); addCriterion("project_id like", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotLike(String value) { public Criteria andProjectIdNotLike(String value) {
addCriterion("scenario_id not like", value, "scenarioId"); addCriterion("project_id not like", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIn(List<String> values) { public Criteria andProjectIdIn(List<String> values) {
addCriterion("scenario_id in", values, "scenarioId"); addCriterion("project_id in", values, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotIn(List<String> values) { public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("scenario_id not in", values, "scenarioId"); addCriterion("project_id not in", values, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdBetween(String value1, String value2) { public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("scenario_id between", value1, value2, "scenarioId"); addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotBetween(String value1, String value2) { public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("scenario_id not between", value1, value2, "scenarioId"); addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this; return (Criteria) this;
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<mapper namespace="io.metersphere.base.mapper.ApiScenarioReportDetailMapper"> <mapper namespace="io.metersphere.base.mapper.ApiScenarioReportDetailMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReportDetail"> <resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReportDetail">
<id column="report_id" jdbcType="VARCHAR" property="reportId" /> <id column="report_id" jdbcType="VARCHAR" property="reportId" />
<result column="scenario_id" jdbcType="VARCHAR" property="scenarioId" /> <result column="project_id" jdbcType="VARCHAR" property="projectId" />
</resultMap> </resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioReportDetail"> <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioReportDetail">
<result column="content" jdbcType="LONGVARBINARY" property="content" /> <result column="content" jdbcType="LONGVARBINARY" property="content" />
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
report_id, scenario_id report_id, project_id
</sql> </sql>
<sql id="Blob_Column_List"> <sql id="Blob_Column_List">
content content
...@@ -121,9 +121,9 @@ ...@@ -121,9 +121,9 @@
</if> </if>
</delete> </delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
insert into api_scenario_report_detail (report_id, scenario_id, content insert into api_scenario_report_detail (report_id, project_id, content
) )
values (#{reportId,jdbcType=VARCHAR}, #{scenarioId,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARBINARY} values (#{reportId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARBINARY}
) )
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
...@@ -132,8 +132,8 @@ ...@@ -132,8 +132,8 @@
<if test="reportId != null"> <if test="reportId != null">
report_id, report_id,
</if> </if>
<if test="scenarioId != null"> <if test="projectId != null">
scenario_id, project_id,
</if> </if>
<if test="content != null"> <if test="content != null">
content, content,
...@@ -143,8 +143,8 @@ ...@@ -143,8 +143,8 @@
<if test="reportId != null"> <if test="reportId != null">
#{reportId,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
</if> </if>
<if test="scenarioId != null"> <if test="projectId != null">
#{scenarioId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="content != null"> <if test="content != null">
#{content,jdbcType=LONGVARBINARY}, #{content,jdbcType=LONGVARBINARY},
...@@ -163,8 +163,8 @@ ...@@ -163,8 +163,8 @@
<if test="record.reportId != null"> <if test="record.reportId != null">
report_id = #{record.reportId,jdbcType=VARCHAR}, report_id = #{record.reportId,jdbcType=VARCHAR},
</if> </if>
<if test="record.scenarioId != null"> <if test="record.projectId != null">
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
</if> </if>
<if test="record.content != null"> <if test="record.content != null">
content = #{record.content,jdbcType=LONGVARBINARY}, content = #{record.content,jdbcType=LONGVARBINARY},
...@@ -177,7 +177,7 @@ ...@@ -177,7 +177,7 @@
<update id="updateByExampleWithBLOBs" parameterType="map"> <update id="updateByExampleWithBLOBs" parameterType="map">
update api_scenario_report_detail update api_scenario_report_detail
set report_id = #{record.reportId,jdbcType=VARCHAR}, set report_id = #{record.reportId,jdbcType=VARCHAR},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
content = #{record.content,jdbcType=LONGVARBINARY} content = #{record.content,jdbcType=LONGVARBINARY}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
...@@ -186,7 +186,7 @@ ...@@ -186,7 +186,7 @@
<update id="updateByExample" parameterType="map"> <update id="updateByExample" parameterType="map">
update api_scenario_report_detail update api_scenario_report_detail
set report_id = #{record.reportId,jdbcType=VARCHAR}, set report_id = #{record.reportId,jdbcType=VARCHAR},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR} project_id = #{record.projectId,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
...@@ -194,8 +194,8 @@ ...@@ -194,8 +194,8 @@
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
update api_scenario_report_detail update api_scenario_report_detail
<set> <set>
<if test="scenarioId != null"> <if test="projectId != null">
scenario_id = #{scenarioId,jdbcType=VARCHAR}, project_id = #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="content != null"> <if test="content != null">
content = #{content,jdbcType=LONGVARBINARY}, content = #{content,jdbcType=LONGVARBINARY},
...@@ -205,13 +205,13 @@ ...@@ -205,13 +205,13 @@
</update> </update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
update api_scenario_report_detail update api_scenario_report_detail
set scenario_id = #{scenarioId,jdbcType=VARCHAR}, set project_id = #{projectId,jdbcType=VARCHAR},
content = #{content,jdbcType=LONGVARBINARY} content = #{content,jdbcType=LONGVARBINARY}
where report_id = #{reportId,jdbcType=VARCHAR} where report_id = #{reportId,jdbcType=VARCHAR}
</update> </update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
update api_scenario_report_detail update api_scenario_report_detail
set scenario_id = #{scenarioId,jdbcType=VARCHAR} set project_id = #{projectId,jdbcType=VARCHAR}
where report_id = #{reportId,jdbcType=VARCHAR} where report_id = #{reportId,jdbcType=VARCHAR}
</update> </update>
</mapper> </mapper>
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<mapper namespace="io.metersphere.base.mapper.ApiScenarioReportMapper"> <mapper namespace="io.metersphere.base.mapper.ApiScenarioReportMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReport"> <resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReport">
<id column="id" jdbcType="VARCHAR" property="id" /> <id column="id" jdbcType="VARCHAR" property="id" />
<result column="scenario_id" jdbcType="VARCHAR" property="scenarioId" /> <result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="name" jdbcType="VARCHAR" property="name" /> <result column="name" jdbcType="VARCHAR" property="name" />
<result column="description" jdbcType="VARCHAR" property="description" /> <result column="description" jdbcType="VARCHAR" property="description" />
<result column="create_time" jdbcType="BIGINT" property="createTime" /> <result column="create_time" jdbcType="BIGINT" property="createTime" />
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, scenario_id, `name`, description, create_time, update_time, `status`, user_id, id, project_id, `name`, description, create_time, update_time, `status`, user_id,
trigger_mode trigger_mode
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiScenarioReportExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.base.domain.ApiScenarioReportExample" resultMap="BaseResultMap">
...@@ -105,11 +105,11 @@ ...@@ -105,11 +105,11 @@
</if> </if>
</delete> </delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReport"> <insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReport">
insert into api_scenario_report (id, scenario_id, `name`, insert into api_scenario_report (id, project_id, `name`,
description, create_time, update_time, description, create_time, update_time,
`status`, user_id, trigger_mode `status`, user_id, trigger_mode
) )
values (#{id,jdbcType=VARCHAR}, #{scenarioId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{status,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR} #{status,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}
) )
...@@ -120,8 +120,8 @@ ...@@ -120,8 +120,8 @@
<if test="id != null"> <if test="id != null">
id, id,
</if> </if>
<if test="scenarioId != null"> <if test="projectId != null">
scenario_id, project_id,
</if> </if>
<if test="name != null"> <if test="name != null">
`name`, `name`,
...@@ -149,8 +149,8 @@ ...@@ -149,8 +149,8 @@
<if test="id != null"> <if test="id != null">
#{id,jdbcType=VARCHAR}, #{id,jdbcType=VARCHAR},
</if> </if>
<if test="scenarioId != null"> <if test="projectId != null">
#{scenarioId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="name != null"> <if test="name != null">
#{name,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
...@@ -187,8 +187,8 @@ ...@@ -187,8 +187,8 @@
<if test="record.id != null"> <if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR}, id = #{record.id,jdbcType=VARCHAR},
</if> </if>
<if test="record.scenarioId != null"> <if test="record.projectId != null">
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
</if> </if>
<if test="record.name != null"> <if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR},
...@@ -219,7 +219,7 @@ ...@@ -219,7 +219,7 @@
<update id="updateByExample" parameterType="map"> <update id="updateByExample" parameterType="map">
update api_scenario_report update api_scenario_report
set id = #{record.id,jdbcType=VARCHAR}, set id = #{record.id,jdbcType=VARCHAR},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR}, description = #{record.description,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
...@@ -234,8 +234,8 @@ ...@@ -234,8 +234,8 @@
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReport"> <update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReport">
update api_scenario_report update api_scenario_report
<set> <set>
<if test="scenarioId != null"> <if test="projectId != null">
scenario_id = #{scenarioId,jdbcType=VARCHAR}, project_id = #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="name != null"> <if test="name != null">
`name` = #{name,jdbcType=VARCHAR}, `name` = #{name,jdbcType=VARCHAR},
...@@ -263,7 +263,7 @@ ...@@ -263,7 +263,7 @@
</update> </update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReport"> <update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReport">
update api_scenario_report update api_scenario_report
set scenario_id = #{scenarioId,jdbcType=VARCHAR}, set project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR}, `name` = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
......
package io.metersphere.base.mapper.ext;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtApiScenarioReportMapper {
List<APIScenarioReportResult> list(@Param("request") QueryAPIReportRequest request);
APIReportResult get(@Param("reportId") String reportId);
}
\ No newline at end of file
<?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.ext.ExtApiScenarioReportMapper">
<resultMap id="BaseResultMap" type="io.metersphere.api.dto.automation.APIScenarioReportResult"
extends="io.metersphere.base.mapper.ApiScenarioReportMapper.BaseResultMap">
<result column="test_name" property="testName"/>
<result column="project_name" property="projectName"/>
<result column="user_name" property="userName"/>
</resultMap>
<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>
<sql id="combine">
<if test='${condition}.name != null and (${name} == null or ${name} == "")'>
and r.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.testName != null">
and t.name
<include refid="condition">
<property name="object" value="${condition}.testName"/>
</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 r.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.status != null">
and r.status
<include refid="condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test="${condition}.triggerMode != null">
and r.trigger_mode
<include refid="condition">
<property name="object" value="${condition}.triggerMode"/>
</include>
</if>
<if test="${condition}.creator != null">
and r.user_id
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
</sql>
<select id="list" resultMap="BaseResultMap">
SELECT r.name AS test_name,
r.name, r.description, r.id, r.project_id, r.create_time, r.update_time, r.status, r.trigger_mode,
project.name AS project_name, user.name AS user_name
FROM api_scenario_report r
LEFT JOIN project ON project.id = r.project_id
LEFT JOIN user ON user.id = r.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 r.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.userId != null">
AND r.user_id = #{request.userId,jdbcType=VARCHAR}
</if>
<if test="request.projectId != null">
AND project.id = #{request.projectId}
</if>
<if test="request.workspaceId != null">
AND project.workspace_id = #{request.workspaceId,jdbcType=VARCHAR}
</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">
<choose>
<when test="key=='status'">
and r.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<otherwise>
and r.trigger_mode in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</otherwise>
</choose>
</if>
</foreach>
</if>
AND r.status != 'Debug'
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
r.${order.name} ${order.type}
</foreach>
</if>
</select>
<select id="get" resultType="io.metersphere.api.dto.APIReportResult">
SELECT r.*,r.id As testId, r.name AS test_name, project.name AS project_name, user.name AS user_name
FROM api_scenario_report r
LEFT JOIN project ON project.id = r.project_id
LEFT JOIN user ON user.id = r.user_id
<where>
r.id = #{reportId}
</where>
ORDER BY r.update_time DESC
</select>
</mapper>
\ No newline at end of file
...@@ -64,10 +64,8 @@ ...@@ -64,10 +64,8 @@
<!--要生成的数据库表 --> <!--要生成的数据库表 -->
<table tableName="schedule"/> <table tableName="api_scenario_report"/>
<table tableName="notice"/> <table tableName="api_scenario_report_detail"/>
<table tableName="message_task"/>
<table tableName="test_plan"/>
</context> </context>
</generatorConfiguration> </generatorConfiguration>
\ No newline at end of file
...@@ -4,12 +4,12 @@ ...@@ -4,12 +4,12 @@
<el-card> <el-card>
<section class="report-container" v-if="this.report.testId"> <section class="report-container" v-if="this.report.testId">
<ms-api-report-view-header :report="report" @reportExport="handleExport"/> <ms-api-report-view-header :report="report" @reportExport="handleExport" @reportSave="handleSave"/>
<main v-if="this.isNotRunning"> <main v-if="this.isNotRunning">
<ms-metric-chart :content="content" :totalTime="totalTime"/> <ms-metric-chart :content="content" :totalTime="totalTime"/>
<div @click="active"> <div>
<ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/> <ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/>
</div> </div>
<el-collapse-transition> <el-collapse-transition>
<div v-show="isActive" style="width: 99%"> <div v-show="isActive" style="width: 99%">
...@@ -64,10 +64,14 @@ ...@@ -64,10 +64,14 @@
requestType: undefined, requestType: undefined,
} }
}, },
props: ['reportId'],
activated() { activated() {
this.isRequestResult = false; this.isRequestResult = false;
}, },
props: {
reportId: String,
currentProjectId: String,
infoDb: Boolean,
},
watch: { watch: {
reportId() { reportId() {
this.getReport(); this.getReport();
...@@ -91,7 +95,7 @@ ...@@ -91,7 +95,7 @@
getReport() { getReport() {
this.init(); this.init();
if (this.reportId) { if (this.reportId) {
let url = "/api/scenario/report/get/" + this.reportId; let url = "/api/scenario/report/get/" + this.reportId + "/" + this.infoDb;
this.$get(url, response => { this.$get(url, response => {
this.report = response.data || {}; this.report = response.data || {};
if (response.data) { if (response.data) {
...@@ -99,7 +103,6 @@ ...@@ -99,7 +103,6 @@
try { try {
this.content = JSON.parse(this.report.content); this.content = JSON.parse(this.report.content);
} catch (e) { } catch (e) {
// console.log(this.report.content)
throw e; throw e;
} }
this.getFails(); this.getFails();
...@@ -136,6 +139,7 @@ ...@@ -136,6 +139,7 @@
} }
}, },
requestResult(requestResult) { requestResult(requestResult) {
this.active();
this.isRequestResult = false; this.isRequestResult = false;
this.requestType = undefined; this.requestType = undefined;
if (requestResult.request.body.indexOf('[Callable Statement]') > -1) { if (requestResult.request.body.indexOf('[Callable Statement]') > -1) {
...@@ -155,6 +159,27 @@ ...@@ -155,6 +159,27 @@
reset(); reset();
}); });
}, },
handleSave() {
if (!this.report.name) {
this.$warning(this.$t('api_test.automation.report_name_info'));
return;
}
if (!this.currentProjectId) {
this.$warning(this.$t('api_test.select_project'));
return;
}
this.loading = true;
this.report.projectId = this.currentProjectId;
let url = "/api/scenario/report/add";
if (this.infoDb === true) {
url = "/api/scenario/report/update";
}
this.result = this.$post(url, this.report, response => {
this.$success(this.$t('commons.save_success'));
this.loading = false;
this.$emit('refresh');
});
},
exportReportReset() { exportReportReset() {
this.$router.go(0); this.$router.go(0);
} }
......
<template>
<ms-container>
<ms-main-container>
<el-card class="table-card" v-loading="result.loading">
<template v-slot:header>
<ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="search"
:title="$t('api_report.title')"
:show-create="false"/>
</template>
<el-table border :data="tableData" class="adjust-table table-content" @sort-change="sort"
@select-all="handleSelectAll"
@select="handleSelect"
@filter-change="filter" @row-click="handleView">
<el-table-column
type="selection"/>
<el-table-column width="40" :resizable="false" align="center">
<template v-slot:default="scope">
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>
</template>
</el-table-column>
<el-table-column :label="$t('commons.name')" width="200" show-overflow-tooltip prop="name">
</el-table-column>
<!--
<el-table-column prop="testName" :label="$t('api_report.test_name')" width="200" show-overflow-tooltip/>
-->
<el-table-column prop="projectName" :label="$t('load_test.project_name')" width="150" show-overflow-tooltip/>
<el-table-column prop="userName" :label="$t('api_test.creator')" width="150" show-overflow-tooltip/>
<el-table-column prop="createTime" width="250" :label="$t('commons.create_time')" sortable>
<template v-slot:default="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column prop="triggerMode" width="150" :label="$t('commons.trigger_mode.name')"
column-key="triggerMode" :filters="triggerFilters">
<template v-slot:default="scope">
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
</template>
</el-table-column>
<el-table-column prop="status" :label="$t('commons.status')"
column-key="status"
:filters="statusFilters">
<template v-slot:default="{row}">
<ms-api-report-status :row="row"/>
</template>
</el-table-column>
<el-table-column width="150" :label="$t('commons.operating')">
<template v-slot:default="scope">
<ms-table-operator-button :tip="$t('api_report.detail')" icon="el-icon-s-data"
@exec="handleView(scope.row)" type="primary"/>
<ms-table-operator-button :is-tester-permission="true" :tip="$t('api_report.delete')"
icon="el-icon-delete" @exec="handleDelete(scope.row)" type="danger"/>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
</el-card>
</ms-main-container>
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProjectId" :info-db="true" @refresh="search"/>
</el-drawer>
</ms-container>
</template>
<script>
import MsTablePagination from "../../../common/pagination/TablePagination";
import MsTableHeader from "../../../common/components/MsTableHeader";
import MsContainer from "../../../common/components/MsContainer";
import MsMainContainer from "../../../common/components/MsMainContainer";
import MsApiReportStatus from "./ApiReportStatus";
import {_filter, _sort} from "@/common/js/utils";
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
import ReportTriggerModeItem from "../../../common/tableItem/ReportTriggerModeItem";
import {REPORT_CONFIGS} from "../../../common/components/search/search-components";
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
import ShowMoreBtn from "../../../track/case/components/ShowMoreBtn";
import MsApiReportDetail from "./ApiReportDetail";
export default {
components: {
ReportTriggerModeItem,
MsTableOperatorButton,
MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, ShowMoreBtn, MsApiReportDetail
},
data() {
return {
result: {},
reportId: "",
debugVisible: false,
condition: {
components: REPORT_CONFIGS
},
tableData: [],
multipleSelection: [],
currentPage: 1,
pageSize: 5,
total: 0,
loading: false,
currentProjectId: "",
statusFilters: [
{text: 'Saved', value: 'Saved'},
{text: 'Starting', value: 'Starting'},
{text: 'Running', value: 'Running'},
{text: 'Reporting', value: 'Reporting'},
{text: 'Completed', value: 'Completed'},
{text: 'Error', value: 'Error'},
{text: 'Success', value: 'Success'},
],
triggerFilters: [
{text: this.$t('commons.trigger_mode.manual'), value: 'MANUAL'},
{text: this.$t('commons.trigger_mode.schedule'), value: 'SCHEDULE'},
{text: this.$t('commons.trigger_mode.api'), value: 'API'}
],
buttons: [
{
name: this.$t('api_report.batch_delete'), handleClick: this.handleBatchDelete
}
],
selectRows: new Set(),
}
},
watch: {
'$route': 'init',
},
methods: {
search() {
if (this.testId !== 'all') {
this.condition.testId = this.testId;
}
let url = "/api/scenario/report/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.selectRows.clear();
});
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleView(report) {
this.reportId = report.id;
this.currentProjectId = report.projectId;
this.debugVisible = true;
},
handleDelete(report) {
this.$alert(this.$t('api_report.delete_confirm') + report.name + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.result = this.$post("/api/scenario/report/delete", {id: report.id}, () => {
this.$success(this.$t('commons.delete_success'));
this.search();
// 发送广播,刷新 head 上的最新列表
ApiEvent.$emit(LIST_CHANGE);
});
}
}
});
},
init() {
this.testId = this.$route.params.testId;
this.search();
},
sort(column) {
_sort(column, this.condition);
this.init();
},
filter(filters) {
_filter(filters, this.condition);
this.init();
},
handleSelect(selection, row) {
if (this.selectRows.has(row)) {
this.$set(row, "showMore", false);
this.selectRows.delete(row);
} else {
this.$set(row, "showMore", true);
this.selectRows.add(row);
}
},
handleSelectAll(selection) {
if (selection.length > 0) {
this.tableData.forEach(item => {
this.$set(item, "showMore", true);
this.selectRows.add(item);
});
} else {
this.selectRows.clear();
this.tableData.forEach(row => {
this.$set(row, "showMore", false);
})
}
},
handleBatchDelete() {
this.$alert(this.$t('api_report.delete_batch_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/api/scenario/report/batch/delete', {ids: ids}, () => {
this.selectRows.clear();
this.$success(this.$t('commons.delete_success'));
this.search();
// 发送广播,刷新 head 上的最新列表
ApiEvent.$emit(LIST_CHANGE);
});
}
}
});
}
},
created() {
this.init();
}
}
</script>
<style scoped>
.table-content {
width: 100%;
}
</style>
...@@ -2,13 +2,17 @@ ...@@ -2,13 +2,17 @@
<header class="report-header"> <header class="report-header">
<el-row> <el-row>
<el-col> <el-col>
<span>{{ report.projectName === null || report.projectName ==='' ? "场景执行报告": report.projectName}} / </span> <span><el-input size="mini" style="width: 200px" v-model="report.name"/> </span>
<router-link :to="path">{{ report.testName }}</router-link>
<span class="time"> {{ report.createTime | timestampFormatDate }}</span> <span class="time"> {{ report.createTime | timestampFormatDate }}</span>
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)"
style="margin-left: 1200px"> <el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)" style="margin-right: 10px">
{{$t('test_track.plan_view.export_report')}} {{$t('test_track.plan_view.export_report')}}
</el-button> </el-button>
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleSave(report.name)" style="margin-right: 10px">
{{$t('commons.save')}}
</el-button>
</el-col> </el-col>
</el-row> </el-row>
</header> </header>
...@@ -38,6 +42,9 @@ ...@@ -38,6 +42,9 @@
methods: { methods: {
handleExport(name) { handleExport(name) {
this.$emit('reportExport', name); this.$emit('reportExport', name);
},
handleSave(name) {
this.$emit('reportSave', name);
} }
} }
} }
......
<template> <template>
<div class="scenario-result"> <div class="scenario-result">
<div v-for="(request, index) in scenario.requestResults" :key="index">
<ms-request-result :key="index" :request="request" :indexNumber="index" <div @click="active">
v-on:requestResult="requestResult" <el-row :gutter="10" type="flex" align="middle" class="info">
:scenarioName="scenario.name"/> <el-col :span="16">
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
{{scenario.name}}
</el-col>
</el-row>
</div> </div>
<el-collapse-transition>
<div v-show="isActive">
<div v-for="(request, index) in scenario.requestResults" :key="index">
<ms-request-result :key="index" :request="request" :indexNumber="index"
v-on:requestResult="requestResult"
:scenarioName="scenario.name"/>
</div>
</div>
</el-collapse-transition>
</div> </div>
</template> </template>
......
<template> <template>
<el-card class="table-card" v-loading="result.loading"> <div>
<template v-slot:header> <el-card class="table-card" v-loading="result.loading">
<ms-table-header :condition.sync="condition" @search="search" title="" <template v-slot:header>
:show-create="false"/> <ms-table-header :condition.sync="condition" @search="search" title=""
</template> :show-create="false"/>
</template>
<el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="select" @select="select"> <el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="select" @select="select">
<el-table-column type="selection"/> <el-table-column type="selection"/>
<el-table-column width="40" :resizable="false" align="center"> <el-table-column width="40" :resizable="false" align="center">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<show-more-btn :is-show="isSelect(row)" :buttons="buttons" :size="selection.length"/> <show-more-btn :is-show="isSelect(row)" :buttons="buttons" :size="selection.length"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="name" :label="$t('api_test.automation.scenario_name')" <el-table-column prop="name" :label="$t('api_test.automation.scenario_name')"
show-overflow-tooltip/> show-overflow-tooltip/>
<el-table-column prop="level" :label="$t('api_test.automation.case_level')" <el-table-column prop="level" :label="$t('api_test.automation.case_level')"
show-overflow-tooltip> show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-tag v-if="scope.row.level == 'P0'" type="info" effect="plain" content="P0"/> <ms-tag v-if="scope.row.level == 'P0'" type="info" effect="plain" content="P0"/>
<ms-tag v-if="scope.row.level == 'P1'" type="warning" effect="plain" content="P1"/> <ms-tag v-if="scope.row.level == 'P1'" type="warning" effect="plain" content="P1"/>
<ms-tag v-if="scope.row.level == 'P2'" type="success" effect="plain" content="P2"/> <ms-tag v-if="scope.row.level == 'P2'" type="success" effect="plain" content="P2"/>
<ms-tag v-if="scope.row.level == 'P3'" type="danger" effect="plain" content="P3"/> <ms-tag v-if="scope.row.level == 'P3'" type="danger" effect="plain" content="P3"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="tagName" :label="$t('api_test.automation.tag')" show-overflow-tooltip> <el-table-column prop="tagName" :label="$t('api_test.automation.tag')" show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-tag type="success" effect="plain" v-if="scope.row.tagName!=undefined" :content="scope.row.tagName"/> <ms-tag type="success" effect="plain" v-if="scope.row.tagName!=undefined" :content="scope.row.tagName"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="userId" :label="$t('api_test.automation.creator')" show-overflow-tooltip/> <el-table-column prop="userId" :label="$t('api_test.automation.creator')" show-overflow-tooltip/>
<el-table-column prop="updateTime" :label="$t('api_test.automation.update_time')" width="180"> <el-table-column prop="updateTime" :label="$t('api_test.automation.update_time')" width="180">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span> <span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/> <el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/>
<el-table-column prop="status" :label="$t('api_test.automation.last_result')"> <el-table-column prop="status" :label="$t('api_test.automation.last_result')">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<el-link type="success" v-if="row.status === 'Success'">{{ $t('api_test.automation.success') }}</el-link> <el-link type="success" v-if="row.status === 'Success'">{{ $t('api_test.automation.success') }}</el-link>
<el-link type="danger" v-if="row.status === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link> <el-link type="danger" v-if="row.status === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link>
<el-link type="warning" v-if="row.status === 'Trash'">{{ $t('api_test.automation.trash') }}</el-link> <el-link type="warning" v-if="row.status === 'Trash'">{{ $t('api_test.automation.trash') }}</el-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="passingRate" :label="$t('api_test.automation.passing_rate')" <el-table-column prop="passingRate" :label="$t('api_test.automation.passing_rate')"
show-overflow-tooltip/> show-overflow-tooltip/>
<el-table-column :label="$t('commons.operating')" width="180"> <el-table-column :label="$t('commons.operating')" width="180">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<el-button type="text" @click="edit(row)">{{ $t('api_test.automation.edit') }}</el-button> <el-button type="text" @click="edit(row)">{{ $t('api_test.automation.edit') }}</el-button>
<el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button> <el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button>
<el-button type="text" @click="copy(row)">{{ $t('api_test.automation.copy') }}</el-button> <el-button type="text" @click="copy(row)">{{ $t('api_test.automation.copy') }}</el-button>
<el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button> <el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" <ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/> :total="total"/>
</el-card>
<div>
<!-- 调试结果 -->
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProject!=undefined ? currentProject.id:''"/>
</el-drawer>
</div>
</el-card>
</div>
</template> </template>
<script> <script>
...@@ -65,10 +75,11 @@ ...@@ -65,10 +75,11 @@
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn"; import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import MsTag from "../../../common/components/MsTag"; import MsTag from "../../../common/components/MsTag";
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsApiReportDetail from "../report/ApiReportDetail";
export default { export default {
name: "MsApiScenarioList", name: "MsApiScenarioList",
components: {ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag}, components: {ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag, MsApiReportDetail},
props: { props: {
currentProject: Object, currentProject: Object,
currentModule: Object, currentModule: Object,
...@@ -83,6 +94,9 @@ ...@@ -83,6 +94,9 @@
currentPage: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
total: 0, total: 0,
reportId: "",
runVisible: false,
runData: [],
buttons: [ buttons: [
{ {
name: this.$t('api_test.automation.batch_add_plan'), handleClick: this.handleBatchAddCase name: this.$t('api_test.automation.batch_add_plan'), handleClick: this.handleBatchAddCase
...@@ -140,7 +154,16 @@ ...@@ -140,7 +154,16 @@
}, },
handleBatchExecute() { handleBatchExecute() {
let url = "/api/automation/run";
let run = {};
let scenarioIds = this.selection;
run.id = getUUID();
run.scenarioIds = scenarioIds;
this.result = this.$post(url, run, response => {
let data = response.data;
this.runVisible = true;
this.reportId = run.id;
});
}, },
selectAllChange() { selectAllChange() {
this.handleCommand("table"); this.handleCommand("table");
...@@ -156,7 +179,17 @@ ...@@ -156,7 +179,17 @@
this.$emit('edit', row); this.$emit('edit', row);
}, },
execute(row) { execute(row) {
let url = "/api/automation/run";
let run = {};
let scenarioIds = [];
scenarioIds.push(row.id);
run.id = getUUID();
run.scenarioIds = scenarioIds;
this.result = this.$post(url, run, response => {
let data = response.data;
this.runVisible = true;
this.reportId = run.id;
});
}, },
copy(row) { copy(row) {
row.id = getUUID(); row.id = getUUID();
......
...@@ -3,17 +3,16 @@ ...@@ -3,17 +3,16 @@
</template> </template>
<script> <script>
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import ThreadGroup from "../../definition/components/jmeter/components/thread-group"; import {createComponent} from "../../definition/components/jmeter/components";
import TestPlan from "../../definition/components/jmeter/components/test-plan";
export default { export default {
name: 'MsRun', name: 'MsDebugRun',
components: {}, components: {},
props: { props: {
environment: String, environment: String,
debug: Boolean, debug: Boolean,
reportId: String, reportId: String,
runData: Array, runData: Object,
}, },
data() { data() {
return { return {
...@@ -31,82 +30,71 @@ ...@@ -31,82 +30,71 @@
} }
}, },
methods: { methods: {
getResult() { setFiles(item, bodyUploadFiles, obj) {
if (this.runId) { if (item.body) {
let url = ""; item.body.kvs.forEach(param => {
if (this.debug) { if (param.files) {
url = "/api/definition/report/get/" + this.runId + "/" + "debug"; param.files.forEach(item => {
} else { if (item.file) {
url = "/api/definition/report/get/" + this.runId + "/" + "run"; if (!item.id) {
} let fileId = getUUID().substring(0, 12);
this.$get(url, response => { item.name = item.file.name;
if (response.data) { item.id = fileId;
let data = JSON.parse(response.data.content); }
this.$emit('runRefresh', data); obj.bodyUploadIds.push(item.id);
} else { bodyUploadFiles.push(item.file);
if (this.reqNumber < 60) { }
this.reqNumber++; });
setTimeout(this.getResult, 2000); }
} else { });
this.$error("获取报告超时"); item.body.binary.forEach(param => {
this.$emit('runRefresh', {}); if (param.files) {
} param.files.forEach(item => {
if (item.file) {
if (!item.id) {
let fileId = getUUID().substring(0, 12);
item.name = item.file.name;
item.id = fileId;
}
obj.bodyUploadIds.push(item.id);
bodyUploadFiles.push(item.file);
}
});
} }
}); });
} }
}, },
recursiveFile(arr, bodyUploadFiles, obj) {
arr.forEach(item => {
this.setFiles(item, bodyUploadFiles, obj);
if (item.hashTree != undefined && item.hashTree.length > 0) {
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
}
});
},
getBodyUploadFiles(obj) { getBodyUploadFiles(obj) {
let bodyUploadFiles = []; let bodyUploadFiles = [];
obj.bodyUploadIds = []; obj.bodyUploadIds = [];
this.runData.forEach(request => { let request = this.runData;
if (request.body) { request.hashTree.forEach(item => {
request.body.kvs.forEach(param => { this.setFiles(item, bodyUploadFiles, obj);
if (param.files) { if (item.hashTree != undefined && item.hashTree.length > 0) {
param.files.forEach(item => { this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
if (item.file) {
if (!item.id) {
let fileId = getUUID().substring(0, 12);
item.name = item.file.name;
item.id = fileId;
}
obj.bodyUploadIds.push(item.id);
bodyUploadFiles.push(item.file);
}
});
}
});
request.body.binary.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
if (!item.id) {
let fileId = getUUID().substring(0, 12);
item.name = item.file.name;
item.id = fileId;
}
obj.bodyUploadIds.push(item.id);
bodyUploadFiles.push(item.file);
}
});
}
});
} }
}); })
return bodyUploadFiles; return bodyUploadFiles;
}, },
run() { run() {
let testPlan = new TestPlan(); let testPlan = createComponent('TestPlan');
this.runData.forEach(item => { let threadGroup = createComponent('ThreadGroup');
let threadGroup = new ThreadGroup(); threadGroup.hashTree = [];
threadGroup.hashTree = []; threadGroup.name = this.runData.name;
threadGroup.name = item.name; threadGroup.hashTree.push(this.runData);
threadGroup.hashTree.push(item); testPlan.hashTree.push(threadGroup);
testPlan.hashTree.push(threadGroup);
})
console.log("====",testPlan)
let reqObj = {id: this.reportId, reportId: this.reportId, environmentId: this.environment, testElement: testPlan}; let reqObj = {id: this.reportId, reportId: this.reportId, environmentId: this.environment, testElement: testPlan};
let bodyFiles = this.getBodyUploadFiles(reqObj); let bodyFiles = this.getBodyUploadFiles(reqObj);
let url = "/api/automation/run"; console.log(bodyFiles)
let url = "/api/automation/run/debug";
this.$fileUpload(url, null, bodyFiles, reqObj, response => { this.$fileUpload(url, null, bodyFiles, reqObj, response => {
this.runId = response.data; this.runId = response.data;
this.$emit('runRefresh', {}); this.$emit('runRefresh', {});
......
...@@ -261,7 +261,7 @@ ...@@ -261,7 +261,7 @@
@runRefresh="runRefresh" ref="runTest"/> @runRefresh="runRefresh" ref="runTest"/>
<!-- 调试结果 --> <!-- 调试结果 -->
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%"> <el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-api-report-detail :report-id="reportId"/> <ms-api-report-detail :report-id="reportId" :currentProjectId="currentProject.id"/>
</el-drawer> </el-drawer>
</div> </div>
</el-card> </el-card>
...@@ -284,7 +284,7 @@ ...@@ -284,7 +284,7 @@
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig"; import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
import MsAddTag from "./AddTag"; import MsAddTag from "./AddTag";
import MsRun from "./Run"; import MsRun from "./DebugRun";
import MsImportApiScenario from "./ImportApiScenario"; import MsImportApiScenario from "./ImportApiScenario";
import MsApiScenarioComponent from "./ApiScenarioComponent"; import MsApiScenarioComponent from "./ApiScenarioComponent";
import MsApiReportDetail from "../report/ApiReportDetail"; import MsApiReportDetail from "../report/ApiReportDetail";
...@@ -333,7 +333,7 @@ ...@@ -333,7 +333,7 @@
expandedNode: [], expandedNode: [],
scenarioDefinition: [], scenarioDefinition: [],
path: "/api/automation/create", path: "/api/automation/create",
debugData: [], debugData: {},
reportId: "", reportId: "",
} }
}, },
...@@ -539,9 +539,7 @@ ...@@ -539,9 +539,7 @@
this.$error(this.$t('api_test.environment.select_environment')); this.$error(this.$t('api_test.environment.select_environment'));
return; return;
} }
let scenario = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition}; this.debugData = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition};
this.debugData = [];
this.debugData.push(scenario);
this.reportId = getUUID().substring(0, 8); this.reportId = getUUID().substring(0, 8);
}, },
getEnvironments() { getEnvironments() {
...@@ -592,11 +590,68 @@ ...@@ -592,11 +590,68 @@
}); });
return path[0].path; return path[0].path;
}, },
setFiles(item, bodyUploadFiles, obj) {
if (item.body) {
item.body.kvs.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
if (!item.id) {
let fileId = getUUID().substring(0, 12);
item.name = item.file.name;
item.id = fileId;
}
obj.bodyUploadIds.push(item.id);
bodyUploadFiles.push(item.file);
}
});
}
});
item.body.binary.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
if (!item.id) {
let fileId = getUUID().substring(0, 12);
item.name = item.file.name;
item.id = fileId;
}
obj.bodyUploadIds.push(item.id);
bodyUploadFiles.push(item.file);
}
});
}
});
}
},
recursiveFile(arr, bodyUploadFiles, obj) {
arr.forEach(item => {
this.setFiles(item, bodyUploadFiles, obj);
if (item.hashTree != undefined && item.hashTree.length > 0) {
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
}
});
},
getBodyUploadFiles(obj) {
let bodyUploadFiles = [];
obj.bodyUploadIds = [];
this.scenarioDefinition.forEach(item => {
this.setFiles(item, bodyUploadFiles, obj);
if (item.hashTree != undefined && item.hashTree.length > 0) {
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
}
})
return bodyUploadFiles;
},
editScenario() { editScenario() {
this.$refs['currentScenario'].validate((valid) => { this.$refs['currentScenario'].validate((valid) => {
if (valid) { if (valid) {
this.setParameter(); this.setParameter();
this.result = this.$post(this.path, this.currentScenario, () => { let bodyFiles = this.getBodyUploadFiles(this.currentScenario);
console.log(bodyFiles)
console.log(this.currentScenario.bodyUploadIds)
this.$fileUpload(this.path, null, bodyFiles, this.currentScenario, () => {
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
this.path = "/api/automation/update"; this.path = "/api/automation/update";
this.currentScenario.tagId = JSON.parse(this.currentScenario.tagId); this.currentScenario.tagId = JSON.parse(this.currentScenario.tagId);
......
...@@ -12,12 +12,7 @@ export const TYPE = "TestPlan"; ...@@ -12,12 +12,7 @@ export const TYPE = "TestPlan";
export default class TestPlan extends HashTreeElement { export default class TestPlan extends HashTreeElement {
constructor(options = DEFAULT_OPTIONS) { constructor(options = DEFAULT_OPTIONS) {
super(options); super(options);
this.$type = TYPE;
this.type = TYPE; this.type = TYPE;
this.functionalMode = this.initBoolProp('TestPlan.functional_mode', false);
this.serializeThreadGroups = this.initBoolProp('TestPlan.serialize_threadgroups', false);
this.tearDownOnShutdown = this.initBoolProp('TestPlan.tearDown_on_shutdown', true);
this.userDefineClasspath = this.initStringProp('TestPlan.user_define_classpath');
this.hashTree = []; this.hashTree = [];
this.userDefinedVariables = []; this.userDefinedVariables = [];
......
...@@ -11,21 +11,7 @@ export const TYPE = "ThreadGroup"; ...@@ -11,21 +11,7 @@ export const TYPE = "ThreadGroup";
export default class ThreadGroup extends HashTreeElement { export default class ThreadGroup extends HashTreeElement {
constructor(options = DEFAULT_OPTIONS) { constructor(options = DEFAULT_OPTIONS) {
super(options); super(options);
this.$type = TYPE;
this.type = TYPE; this.type = TYPE;
this.onSampleError = this.initStringProp('ThreadGroup.on_sample_error', 'continue');
this.numThreads = this.initStringProp('ThreadGroup.num_threads', 1);
this.rampTime = this.initStringProp('ThreadGroup.ramp_time', 1);
let loopController = this.initElementProp('ThreadGroup.main_controller', 'LoopController');
this.continueForever = loopController.initBoolProp('LoopController.continue_forever', false);
this.loops = loopController.initStringProp('LoopController.loops', 1);
this.sameUserOnNextIteration = this.initBoolProp('ThreadGroup.same_user_on_next_iteration', true);
this.delayedStart = this.initBoolProp('ThreadGroup.delayedStart');
this.scheduler = this.initBoolProp('ThreadGroup.scheduler', false);
this.delay = this.initStringProp('ThreadGroup.delay');
this.duration = this.initStringProp('ThreadGroup.duration');
} }
} }
......
...@@ -15,6 +15,10 @@ ...@@ -15,6 +15,10 @@
{{ $t("i18n.automation") }} {{ $t("i18n.automation") }}
</el-menu-item> </el-menu-item>
<el-menu-item :index="'/api/automation/report'">
{{ $t("i18n.report") }}
</el-menu-item>
<el-submenu :class="{'deactivation':!isProjectActivation}" v-permission="['test_manager','test_user','test_viewer']" index="3"> <el-submenu :class="{'deactivation':!isProjectActivation}" v-permission="['test_manager','test_user','test_viewer']" index="3">
<template v-slot:title>{{ $t('commons.project') }}</template> <template v-slot:title>{{ $t('commons.project') }}</template>
<ms-recent-list ref="projectRecent" :options="projectRecent"/> <ms-recent-list ref="projectRecent" :options="projectRecent"/>
......
...@@ -48,6 +48,11 @@ export default { ...@@ -48,6 +48,11 @@ export default {
path: "automation", path: "automation",
name: "ApiAutomation", name: "ApiAutomation",
component: () => import('@/business/components/api/automation/ApiAutomation'), component: () => import('@/business/components/api/automation/ApiAutomation'),
},
{
path: "automation/report",
name: "ApiReportList",
component: () => import('@/business/components/api/automation/report/ApiReportList'),
} }
] ]
} }
...@@ -163,7 +163,7 @@ export default { ...@@ -163,7 +163,7 @@ export default {
current_user: "Current user" current_user: "Current user"
} }
}, },
monitor:"monitor" monitor: "monitor"
}, },
license: { license: {
title: 'Authorization management', title: 'Authorization management',
...@@ -543,6 +543,7 @@ export default { ...@@ -543,6 +543,7 @@ export default {
customize_script: "Custom script", customize_script: "Custom script",
customize_req: "Custom request", customize_req: "Custom request",
reference_info: "Please select interface or use case", reference_info: "Please select interface or use case",
report_name_info: 'Please enter the registration name',
}, },
environment: { environment: {
name: "Environment Name", name: "Environment Name",
...@@ -779,14 +780,14 @@ export default { ...@@ -779,14 +780,14 @@ export default {
not_exist: "Test report does not exist", not_exist: "Test report does not exist",
}, },
api_monitor: { api_monitor: {
to:"to", to: "to",
start_time:"Start Time", start_time: "Start Time",
end_time:"End Time", end_time: "End Time",
today:"Today", today: "Today",
this_week:"This Week", this_week: "This Week",
this_mouth:"This Mouth", this_mouth: "This Mouth",
please_search:"Please Search", please_search: "Please Search",
date:"Date" date: "Date"
}, },
test_track: { test_track: {
test_track: "Track", test_track: "Track",
...@@ -1096,6 +1097,7 @@ export default { ...@@ -1096,6 +1097,7 @@ export default {
home: 'Home', home: 'Home',
definition: 'Api Definition', definition: 'Api Definition',
automation: 'Api Automation', automation: 'Api Automation',
report: 'Test report',
}, },
ldap: { ldap: {
url: 'LDAP URL', url: 'LDAP URL',
......
...@@ -570,7 +570,8 @@ export default { ...@@ -570,7 +570,8 @@ export default {
follow_people: "关注人", follow_people: "关注人",
select_table: "选择可见数据", select_table: "选择可见数据",
select_all: "选择全部数据" select_all: "选择全部数据"
} },
report_name_info: '请输入报名名称',
}, },
environment: { environment: {
name: "环境名称", name: "环境名称",
...@@ -809,14 +810,14 @@ export default { ...@@ -809,14 +810,14 @@ export default {
not_exist: "测试报告不存在", not_exist: "测试报告不存在",
}, },
api_monitor: { api_monitor: {
to:"", to: "",
start_time:"开始日期", start_time: "开始日期",
end_time:"结束日期", end_time: "结束日期",
today:"今日", today: "今日",
this_week:"本周", this_week: "本周",
this_mouth:"本月", this_mouth: "本月",
please_search:"请搜索", please_search: "请搜索",
date:"日期" date: "日期"
}, },
test_track: { test_track: {
test_track: "测试跟踪", test_track: "测试跟踪",
...@@ -1125,6 +1126,7 @@ export default { ...@@ -1125,6 +1126,7 @@ export default {
home: '首页', home: '首页',
definition: '接口定义', definition: '接口定义',
automation: '接口自动化', automation: '接口自动化',
report: '测试报告',
}, },
ldap: { ldap: {
url: 'LDAP地址', url: 'LDAP地址',
......
...@@ -543,8 +543,8 @@ export default { ...@@ -543,8 +543,8 @@ export default {
scenario_import: "場景導入", scenario_import: "場景導入",
customize_script: "自定義腳本", customize_script: "自定義腳本",
customize_req: "自定義請求", customize_req: "自定義請求",
reference_info: "請選擇接口或用例" reference_info: "請選擇接口或用例",
report_name_info: '请输入报名名称',
}, },
environment: { environment: {
name: "環境名稱", name: "環境名稱",
...@@ -1098,6 +1098,7 @@ export default { ...@@ -1098,6 +1098,7 @@ export default {
home: '首頁', home: '首頁',
definition: '接口定義', definition: '接口定義',
automation: '接口自動化', automation: '接口自動化',
report: '測試報告',
}, },
ldap: { ldap: {
url: 'LDAP地址', url: 'LDAP地址',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册