Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
cf9e263588
|
@ -1,5 +1,7 @@
|
|||
package io.metersphere.engine;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface Engine {
|
||||
Long getStartTime();
|
||||
|
||||
|
@ -8,4 +10,6 @@ public interface Engine {
|
|||
void start();
|
||||
|
||||
void stop();
|
||||
|
||||
Map<String, String> log();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@ import io.metersphere.engine.docker.request.TestRequest;
|
|||
import io.metersphere.i18n.Translator;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DockerTestEngine extends AbstractEngine {
|
||||
|
@ -98,7 +100,22 @@ public class DockerTestEngine extends AbstractEngine {
|
|||
String uri = String.format(BASE_URL + "/jmeter/container/stop/" + testId, ip, port);
|
||||
restTemplate.postForObject(uri, request, String.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> log() {
|
||||
String testId = loadTest.getId();
|
||||
Map<String, String> logs = new HashMap<>();
|
||||
BaseRequest request = new BaseRequest();
|
||||
this.resourceList.forEach(r -> {
|
||||
NodeDTO node = JSON.parseObject(r.getConfiguration(), NodeDTO.class);
|
||||
String ip = node.getIp();
|
||||
Integer port = node.getPort();
|
||||
|
||||
String uri = String.format(BASE_URL + "/jmeter/container/log/" + testId, ip, port);
|
||||
String log = restTemplate.postForObject(uri, request, String.class);
|
||||
logs.put(node.getIp(), log);
|
||||
});
|
||||
return logs;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
package io.metersphere.engine.docker.request;
|
||||
|
||||
public class BaseRequest {
|
||||
private String testId;
|
||||
|
||||
public String getTestId() {
|
||||
return testId;
|
||||
}
|
||||
|
||||
public void setTestId(String testId) {
|
||||
this.testId = testId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ public class TestRequest extends BaseRequest {
|
|||
|
||||
private int size;
|
||||
private String fileString;
|
||||
private String testId;
|
||||
private String image;
|
||||
private Map<String, String> testData = new HashMap<>();
|
||||
|
||||
|
@ -27,14 +26,6 @@ public class TestRequest extends BaseRequest {
|
|||
this.fileString = fileString;
|
||||
}
|
||||
|
||||
public String getTestId() {
|
||||
return testId;
|
||||
}
|
||||
|
||||
public void setTestId(String testId) {
|
||||
this.testId = testId;
|
||||
}
|
||||
|
||||
public String getImage() {
|
||||
return image;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import io.metersphere.i18n.Translator;
|
|||
import org.apache.commons.collections.MapUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class KubernetesTestEngine extends AbstractEngine {
|
||||
|
||||
|
@ -122,4 +123,23 @@ public class KubernetesTestEngine extends AbstractEngine {
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> log() {
|
||||
Map<String, String> logs = new HashMap<>();
|
||||
resourceList.forEach(r -> {
|
||||
try {
|
||||
String configuration = r.getConfiguration();
|
||||
ClientCredential clientCredential = JSON.parseObject(configuration, ClientCredential.class);
|
||||
KubernetesProvider provider = new KubernetesProvider(JSON.toJSONString(clientCredential));
|
||||
provider.confirmNamespace(loadTest.getProjectId());
|
||||
String joblog = provider.getKubernetesClient().batch().jobs().inNamespace(loadTest.getProjectId()).withName("job-" + loadTest.getId()).getLog();
|
||||
logs.put(clientCredential.getMasterUrl(), joblog);
|
||||
} catch (Exception e) {
|
||||
MSException.throwException(e);
|
||||
}
|
||||
|
||||
});
|
||||
return logs;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,8 +93,6 @@ public class PerformanceTestService {
|
|||
loadTest.setProjectId(request.getProjectId());
|
||||
loadTest.setCreateTime(System.currentTimeMillis());
|
||||
loadTest.setUpdateTime(System.currentTimeMillis());
|
||||
loadTest.setScenarioDefinition("todo");
|
||||
loadTest.setDescription("todo");
|
||||
loadTest.setTestResourcePoolId(request.getTestResourcePoolId());
|
||||
loadTest.setLoadConfiguration(request.getLoadConfiguration());
|
||||
loadTest.setAdvancedConfiguration(request.getAdvancedConfiguration());
|
||||
|
@ -133,6 +131,14 @@ public class PerformanceTestService {
|
|||
}
|
||||
|
||||
public String edit(EditTestPlanRequest request, List<MultipartFile> files) {
|
||||
//
|
||||
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId());
|
||||
if (loadTest == null) {
|
||||
MSException.throwException(Translator.get("edit_load_test_not_found") + request.getId());
|
||||
}
|
||||
if (StringUtils.containsAny(loadTest.getStatus(), PerformanceTestStatus.Running.name(), PerformanceTestStatus.Starting.name())) {
|
||||
MSException.throwException(Translator.get("cannot_edit_load_test_running"));
|
||||
}
|
||||
// 新选择了一个文件,删除原来的文件
|
||||
List<FileMetadata> updatedFiles = request.getUpdatedFileList();
|
||||
List<FileMetadata> originFiles = fileService.getFileMetadataByTestId(request.getId());
|
||||
|
@ -152,22 +158,14 @@ public class PerformanceTestService {
|
|||
});
|
||||
}
|
||||
|
||||
final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId());
|
||||
if (loadTest == null) {
|
||||
MSException.throwException(Translator.get("edit_load_test_not_found") + request.getId());
|
||||
} else {
|
||||
loadTest.setName(request.getName());
|
||||
loadTest.setProjectId(request.getProjectId());
|
||||
loadTest.setUpdateTime(System.currentTimeMillis());
|
||||
loadTest.setScenarioDefinition("todo");
|
||||
loadTest.setDescription("todo");
|
||||
loadTest.setLoadConfiguration(request.getLoadConfiguration());
|
||||
loadTest.setAdvancedConfiguration(request.getAdvancedConfiguration());
|
||||
loadTest.setTestResourcePoolId(request.getTestResourcePoolId());
|
||||
// todo 修改 load_test 的时候排除状态,这里存在修改了 Running 的测试状态的风险
|
||||
// loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
}
|
||||
loadTest.setName(request.getName());
|
||||
loadTest.setProjectId(request.getProjectId());
|
||||
loadTest.setUpdateTime(System.currentTimeMillis());
|
||||
loadTest.setLoadConfiguration(request.getLoadConfiguration());
|
||||
loadTest.setAdvancedConfiguration(request.getAdvancedConfiguration());
|
||||
loadTest.setTestResourcePoolId(request.getTestResourcePoolId());
|
||||
loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
|
||||
return request.getId();
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package io.metersphere.service;
|
||||
|
||||
import io.metersphere.base.domain.LoadTestReport;
|
||||
import io.metersphere.base.domain.LoadTestReportExample;
|
||||
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.LoadTestMapper;
|
||||
import io.metersphere.base.mapper.LoadTestReportMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
|
||||
import io.metersphere.commons.constants.PerformanceTestStatus;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.controller.request.ReportRequest;
|
||||
import io.metersphere.dto.ReportDTO;
|
||||
import io.metersphere.engine.Engine;
|
||||
import io.metersphere.engine.EngineFactory;
|
||||
import io.metersphere.report.JtlResolver;
|
||||
import io.metersphere.report.base.ChartsData;
|
||||
import io.metersphere.report.base.Errors;
|
||||
|
@ -31,6 +33,8 @@ public class ReportService {
|
|||
private LoadTestReportMapper loadTestReportMapper;
|
||||
@Resource
|
||||
private ExtLoadTestReportMapper extLoadTestReportMapper;
|
||||
@Resource
|
||||
private LoadTestMapper loadTestMapper;
|
||||
|
||||
public List<LoadTestReport> getRecentReportList(ReportRequest request) {
|
||||
LoadTestReportExample example = new LoadTestReportExample();
|
||||
|
@ -46,9 +50,38 @@ public class ReportService {
|
|||
}
|
||||
|
||||
public void deleteReport(String reportId) {
|
||||
if (StringUtils.isBlank(reportId)) {
|
||||
MSException.throwException("report id cannot be null");
|
||||
}
|
||||
|
||||
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(loadTestReport.getTestId());
|
||||
|
||||
LogUtil.info("Delete report started, report ID: %s" + reportId);
|
||||
|
||||
final Engine engine = EngineFactory.createEngine(loadTest);
|
||||
if (engine == null) {
|
||||
MSException.throwException(String.format("Delete report fail. create engine fail,report ID:%s", reportId));
|
||||
}
|
||||
|
||||
String reportStatus = loadTestReport.getStatus();
|
||||
boolean isRunning = StringUtils.equals(reportStatus, PerformanceTestStatus.Running.name());
|
||||
boolean isStarting = StringUtils.equals(reportStatus, PerformanceTestStatus.Starting.name());
|
||||
boolean isError = StringUtils.equals(reportStatus, PerformanceTestStatus.Error.name());
|
||||
if (isRunning || isStarting || isError) {
|
||||
LogUtil.info("Start stop engine, report status: %s" + reportStatus);
|
||||
stopEngine(loadTest, engine);
|
||||
}
|
||||
|
||||
loadTestReportMapper.deleteByPrimaryKey(reportId);
|
||||
}
|
||||
|
||||
private void stopEngine(LoadTestWithBLOBs loadTest, Engine engine) {
|
||||
engine.stop();
|
||||
loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
}
|
||||
|
||||
public ReportDTO getReportTestAndProInfo(String reportId) {
|
||||
return extLoadTestReportMapper.getReportTestAndProInfo(reportId);
|
||||
}
|
||||
|
|
|
@ -19,3 +19,4 @@ duplicate_node_ip=Duplicate IPs
|
|||
only_one_k8s=Only one K8s can be added
|
||||
organization_id_is_null=Organization ID cannot be null
|
||||
max_thread_insufficient=The number of concurrent users exceeds
|
||||
cannot_edit_load_test_running=Cannot modify the running test
|
|
@ -18,4 +18,5 @@ no_nodes_message=\u6CA1\u6709\u8282\u70B9\u4FE1\u606F
|
|||
duplicate_node_ip=\u8282\u70B9 IP \u91CD\u590D
|
||||
only_one_k8s=\u53EA\u80FD\u6DFB\u52A0\u4E00\u4E2A K8s
|
||||
organization_id_is_null=\u7EC4\u7EC7 ID \u4E0D\u80FD\u4E3A\u7A7A
|
||||
max_thread_insufficient=\u5E76\u53D1\u7528\u6237\u6570\u8D85\u989D
|
||||
max_thread_insufficient=\u5E76\u53D1\u7528\u6237\u6570\u8D85\u989D
|
||||
cannot_edit_load_test_running=不能修改正在运行的测试
|
|
@ -1,43 +1,41 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div class="main-content">
|
||||
<el-container>
|
||||
<el-aside width="250px">
|
||||
<el-card>
|
||||
|
||||
<select-menu
|
||||
:data="projects"
|
||||
:current-data="currentProject"
|
||||
:title="$t('test_track.project')"
|
||||
@dataChange="changeProject">
|
||||
</select-menu>
|
||||
<el-container class="case-container">
|
||||
<el-aside class="tree-aside">
|
||||
<select-menu
|
||||
:data="projects"
|
||||
:current-data="currentProject"
|
||||
:title="$t('test_track.project')"
|
||||
@dataChange="changeProject">
|
||||
</select-menu>
|
||||
<node-tree class="node-tree"
|
||||
:current-project="currentProject"
|
||||
@nodeSelectEvent="refreshTable"
|
||||
@refresh="refreshTable"
|
||||
ref="nodeTree">
|
||||
</node-tree>
|
||||
</el-aside>
|
||||
|
||||
<node-tree class="node-tree"
|
||||
:current-project="currentProject"
|
||||
@nodeSelectEvent="refreshTable"
|
||||
@refresh="refreshTable"
|
||||
ref="nodeTree">
|
||||
</node-tree>
|
||||
<el-main class="case-main">
|
||||
<test-case-list
|
||||
:current-project="currentProject"
|
||||
@openTestCaseEditDialog="openTestCaseEditDialog"
|
||||
@testCaseEdit="openTestCaseEditDialog"
|
||||
@refresh="refresh"
|
||||
ref="testCaseList">
|
||||
</test-case-list>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
</el-aside>
|
||||
|
||||
<el-main class="main-content">
|
||||
|
||||
<test-case-list
|
||||
:current-project="currentProject"
|
||||
@openTestCaseEditDialog="openTestCaseEditDialog"
|
||||
@testCaseEdit="openTestCaseEditDialog"
|
||||
@refresh="refresh"
|
||||
ref="testCaseList">
|
||||
</test-case-list>
|
||||
</el-main>
|
||||
|
||||
</el-container>
|
||||
|
||||
<test-case-edit
|
||||
@refresh="refreshTable"
|
||||
ref="testCaseEditDialog">
|
||||
</test-case-edit>
|
||||
<test-case-edit
|
||||
@refresh="refreshTable"
|
||||
ref="testCaseEditDialog">
|
||||
</test-case-edit>
|
||||
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -174,7 +172,6 @@
|
|||
openRecentTestCaseEditDialog() {
|
||||
let caseId = this.$route.params.caseId;
|
||||
this.getProjectByCaseId(caseId);
|
||||
// this.refresh();
|
||||
this.$get('/test/case/get/' + caseId, response => {
|
||||
if (response.data) {
|
||||
this.openTestCaseEditDialog(response.data);
|
||||
|
@ -206,20 +203,25 @@
|
|||
|
||||
<style scoped>
|
||||
|
||||
.main-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: white;
|
||||
height: 1000px;
|
||||
.node-tree {
|
||||
margin: 3%;
|
||||
}
|
||||
|
||||
|
||||
.tree-aside {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.node-tree {
|
||||
margin: 5%;
|
||||
.case-container {
|
||||
height: calc(100vh - 150px);
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0px;
|
||||
.case-main {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,44 +1,40 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div class="main-content">
|
||||
<el-container>
|
||||
<el-aside class="aside-container" width="250px">
|
||||
<select-menu
|
||||
:data="testPlans"
|
||||
:current-data="currentPlan"
|
||||
:title="$t('test_track.plan')"
|
||||
@dataChange="changePlan">
|
||||
</select-menu>
|
||||
<el-card>
|
||||
<el-container class="view-container">
|
||||
<el-aside class="tree-aside">
|
||||
<select-menu
|
||||
:data="testPlans"
|
||||
:current-data="currentPlan"
|
||||
:title="$t('test_track.plan')"
|
||||
@dataChange="changePlan">
|
||||
</select-menu>
|
||||
|
||||
<plan-node-tree
|
||||
class="node-tree"
|
||||
:plan-id="planId"
|
||||
@nodeSelectEvent="getPlanCases"
|
||||
ref="tree">
|
||||
</plan-node-tree>
|
||||
<plan-node-tree
|
||||
class="node-tree"
|
||||
:plan-id="planId"
|
||||
@nodeSelectEvent="getPlanCases"
|
||||
ref="tree">
|
||||
</plan-node-tree>
|
||||
|
||||
</el-aside>
|
||||
</el-aside>
|
||||
|
||||
<el-main>
|
||||
<test-plan-test-case-list
|
||||
@openTestCaseRelevanceDialog="openTestCaseRelevanceDialog"
|
||||
@editTestPlanTestCase="editTestPlanTestCase"
|
||||
@refresh="refresh"
|
||||
:plan-id="planId"
|
||||
ref="testCasePlanList"></test-plan-test-case-list>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<test-case-relevance
|
||||
@refresh="refresh"
|
||||
:plan-id="planId"
|
||||
ref="testCaseRelevance"></test-case-relevance>
|
||||
|
||||
<test-plan-test-case-edit
|
||||
ref="testPlanTestCaseEdit"
|
||||
@refresh="refresh">
|
||||
</test-plan-test-case-edit>
|
||||
<el-main class="view-main">
|
||||
<test-plan-test-case-list
|
||||
@openTestCaseRelevanceDialog="openTestCaseRelevanceDialog"
|
||||
@refresh="refresh"
|
||||
:plan-id="planId"
|
||||
ref="testCasePlanList"></test-plan-test-case-list>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<test-case-relevance
|
||||
@refresh="refresh"
|
||||
:plan-id="planId"
|
||||
ref="testCaseRelevance">
|
||||
</test-case-relevance>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -49,12 +45,11 @@
|
|||
import PlanNodeTree from "./components/PlanNodeTree";
|
||||
import TestPlanTestCaseList from "./components/TestPlanTestCaseList";
|
||||
import TestCaseRelevance from "./components/TestCaseRelevance";
|
||||
import TestPlanTestCaseEdit from "./components/TestPlanTestCaseEdit";
|
||||
import SelectMenu from "../common/SelectMenu";
|
||||
|
||||
export default {
|
||||
name: "TestPlanView",
|
||||
components: {PlanNodeTree, TestPlanTestCaseList, TestCaseRelevance, TestPlanTestCaseEdit, SelectMenu},
|
||||
components: {PlanNodeTree, TestPlanTestCaseList, TestCaseRelevance, SelectMenu},
|
||||
data() {
|
||||
return {
|
||||
testPlans: [],
|
||||
|
@ -85,22 +80,6 @@
|
|||
openTestCaseRelevanceDialog() {
|
||||
this.$refs.testCaseRelevance.openTestCaseRelevanceDialog();
|
||||
},
|
||||
editTestPlanTestCase(testCase) {
|
||||
let item = {};
|
||||
Object.assign(item, testCase);
|
||||
item.results = JSON.parse(item.results);
|
||||
item.steps = JSON.parse(item.steps);
|
||||
item.steptResults = [];
|
||||
for (let i = 0; i < item.steps.length; i++){
|
||||
if(item.results[i]){
|
||||
item.steps[i].actualResult = item.results[i].actualResult;
|
||||
item.steps[i].executeResult = item.results[i].executeResult;
|
||||
}
|
||||
item.steptResults.push(item.steps[i]);
|
||||
}
|
||||
this.$refs.testPlanTestCaseEdit.testCase = item;
|
||||
this.$refs.testPlanTestCaseEdit.dialog = true;
|
||||
},
|
||||
getTestPlans() {
|
||||
this.result = this.$post('/test/plan/list/all', {}, response => {
|
||||
this.testPlans = response.data;
|
||||
|
@ -121,22 +100,25 @@
|
|||
|
||||
<style scoped>
|
||||
|
||||
.main-content {
|
||||
padding: 0px;
|
||||
background: white;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.aside-container {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.node-tree {
|
||||
margin: 3%;
|
||||
}
|
||||
|
||||
.view-container {
|
||||
height: calc(100vh - 150px);
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.tree-aside {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.view-main {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
<template>
|
||||
<el-row type="flex" justify="start" :gutter="20">
|
||||
<el-row type="flex" justify="start" :gutter="20" class="status-button">
|
||||
<el-col>
|
||||
<el-button type="success" round
|
||||
<el-button type="success" round size="mini"
|
||||
:icon="status == 'Pass' ? 'el-icon-check' : ''"
|
||||
@click="setStatus('Pass')"> {{$t('test_track.pass')}}</el-button>
|
||||
</el-col>
|
||||
<el-col >
|
||||
<el-button type="danger" round
|
||||
<el-button type="danger" round size="mini"
|
||||
:icon="status == 'Failure' ? 'el-icon-check' : ''"
|
||||
@click="setStatus('Failure')"> {{$t('test_track.failure')}}</el-button>
|
||||
</el-col>
|
||||
<el-col >
|
||||
<el-button type="warning" round
|
||||
<el-button type="warning" round size="mini"
|
||||
:icon="status == 'Blocking' ? 'el-icon-check' : ''"
|
||||
@click="setStatus('Blocking')"> {{$t('test_track.blocking')}}</el-button>
|
||||
</el-col>
|
||||
<el-col >
|
||||
<el-button type="info" round
|
||||
<el-button type="info" round size="mini"
|
||||
:icon="status == 'Skip' ? 'el-icon-check' : ''"
|
||||
@click="setStatus('Skip')"> {{$t('test_track.skip')}}</el-button>
|
||||
</el-col>
|
||||
|
|
|
@ -1,14 +1,55 @@
|
|||
<template>
|
||||
|
||||
<el-drawer
|
||||
:title="testCase.name"
|
||||
:before-close="handleClose"
|
||||
:visible.sync="dialog"
|
||||
direction="ttb"
|
||||
:visible.sync="showDialog"
|
||||
:with-header="false"
|
||||
size="100%"
|
||||
ref="drawer">
|
||||
|
||||
<div class="case_container">
|
||||
<template v-slot:default="scope">
|
||||
|
||||
<el-header>
|
||||
|
||||
<el-row type="flex" class="head-bar">
|
||||
|
||||
<el-col :span="12">
|
||||
<el-button plain size="mini"
|
||||
icon="el-icon-back"
|
||||
@click="cancel">返回</el-button>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="head-right">
|
||||
<span class="head-right-tip" v-if="index + 1 == tableData.length">
|
||||
上一条用例 : {{tableData ? tableData[index - 1].name : ''}}
|
||||
</span>
|
||||
<span class="head-right-tip" v-if="index + 1 < tableData.length">
|
||||
下一条用例 : {{tableData ? tableData[index + 1].name : ''}}
|
||||
</span>
|
||||
|
||||
<el-button plain size="mini" icon="el-icon-arrow-up"
|
||||
:disabled="index + 1 <= 1"
|
||||
@click="handlePre()"/>
|
||||
<span> {{index + 1}}/{{tableData.length}} </span>
|
||||
<el-button plain size="mini" icon="el-icon-arrow-down"
|
||||
:disabled="index + 1 >= tableData.length"
|
||||
@click="handleNext()"/>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
|
||||
<el-button type="primary" size="mini" @click="saveCase">{{$t('test_track.save')}}</el-button>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
||||
<el-row style="margin-top: 0px;">
|
||||
<el-col>
|
||||
<el-divider content-position="left">{{testCase.name}}</el-divider>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-header>
|
||||
|
||||
<div class="case_container">
|
||||
<el-row >
|
||||
<el-col :span="4" :offset="1">
|
||||
<span class="cast_label">{{$t('test_track.priority')}}:</span>
|
||||
|
@ -20,6 +61,11 @@
|
|||
<span class="cast_item" v-if="testCase.type == 'performance'">{{$t('commons.performance')}}</span>
|
||||
<span class="cast_item" v-if="testCase.type == 'api'">{{$t('commons.api')}}</span>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<test-plan-test-case-status-button class="status-button"
|
||||
@statusChange="statusChange"
|
||||
:status="testCase.status"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
|
@ -36,11 +82,15 @@
|
|||
|
||||
<el-row>
|
||||
<el-col :span="20" :offset="1">
|
||||
<div>
|
||||
<span class="cast_label">测试步骤:</span>
|
||||
</div>
|
||||
<el-table
|
||||
:data="testCase.steptResults"
|
||||
class="tb-edit"
|
||||
size="mini"
|
||||
height="200px"
|
||||
height="250px"
|
||||
:border="true"
|
||||
:default-sort = "{prop: 'num', order: 'ascending'}"
|
||||
highlight-current-row>
|
||||
<el-table-column :label="$t('test_track.number')" prop="num" min-width="5%"></el-table-column>
|
||||
|
@ -71,10 +121,10 @@
|
|||
<el-select
|
||||
v-model="scope.row.executeResult"
|
||||
size="mini">
|
||||
<el-option :label="$t('test_track.pass')" value="Pass"></el-option>
|
||||
<el-option :label="$t('test_track.failure')" value="Failure"></el-option>
|
||||
<el-option :label="$t('test_track.blocking')" value="Blocking"></el-option>
|
||||
<el-option :label="$t('test_track.skip')" value="Skip"></el-option>
|
||||
<el-option :label="$t('test_track.pass')" value="Pass" style="color: #7ebf50;"></el-option>
|
||||
<el-option :label="$t('test_track.failure')" value="Failure" style="color: #e57471;"></el-option>
|
||||
<el-option :label="$t('test_track.blocking')" value="Blocking" style="color: #dda451;"></el-option>
|
||||
<el-option :label="$t('test_track.skip')" value="Skip" style="color: #919399;"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -84,7 +134,7 @@
|
|||
|
||||
<el-row>
|
||||
<el-col :span="15" :offset="1">
|
||||
<div style="margin-bottom: 5px;">
|
||||
<div>
|
||||
<span class="cast_label">{{$t('commons.remark')}}:</span>
|
||||
<span v-if="testCase.remark == null || testCase.remark == ''" style="color: darkgrey">{{$t('commons.not_filled')}}</span>
|
||||
</div>
|
||||
|
@ -98,20 +148,9 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<test-plan-test-case-status-button class="status-button"
|
||||
@statusChange="statusChange"
|
||||
:status="testCase.status"/>
|
||||
|
||||
<el-row type="flex" justify="end">
|
||||
<el-col :span="5">
|
||||
<div>
|
||||
<el-button @click="cancel">{{$t('test_track.cancel')}}</el-button>
|
||||
<el-button type="primary" @click="saveCase">{{$t('test_track.save')}}</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
|
||||
</template>
|
||||
|
@ -120,44 +159,77 @@
|
|||
import TestPlanTestCaseStatusButton from '../common/TestPlanTestCaseStatusButton';
|
||||
|
||||
export default {
|
||||
name: "TestPlanTestCaseEdit",
|
||||
name: "TestPlanTestCaseEdit",
|
||||
components: {TestPlanTestCaseStatusButton},
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
testCase: {TestPlanTestCaseStatusButton}
|
||||
};
|
||||
return {
|
||||
showDialog: false,
|
||||
testCase: {},
|
||||
index: 0
|
||||
};
|
||||
},
|
||||
props: {
|
||||
tableData: {
|
||||
type: Array
|
||||
},
|
||||
methods: {
|
||||
handleClose(done) {
|
||||
this.dialog = false;
|
||||
},
|
||||
cancel() {
|
||||
this.dialog = false;
|
||||
},
|
||||
statusChange(status) {
|
||||
this.testCase.status = status;
|
||||
},
|
||||
saveCase() {
|
||||
let param = {};
|
||||
param.id = this.testCase.id;
|
||||
param.status = this.testCase.status;
|
||||
param.results = [];
|
||||
this.testCase.steptResults.forEach(item => {
|
||||
let result = {};
|
||||
result.actualResult = item.actualResult;
|
||||
result.executeResult = item.executeResult;
|
||||
param.results.push(result);
|
||||
});
|
||||
param.results = JSON.stringify(param.results);
|
||||
this.$post('/test/plan/case/edit', param, () => {
|
||||
this.$refs.drawer.closeDrawer();
|
||||
this.$message.success("保存成功!");
|
||||
this.$emit('refresh');
|
||||
});
|
||||
total: {
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClose(done) {
|
||||
this.showDialog = false;
|
||||
},
|
||||
cancel() {
|
||||
this.showDialog = false;
|
||||
},
|
||||
statusChange(status) {
|
||||
this.testCase.status = status;
|
||||
},
|
||||
saveCase() {
|
||||
let param = {};
|
||||
param.id = this.testCase.id;
|
||||
param.status = this.testCase.status;
|
||||
param.results = [];
|
||||
this.testCase.steptResults.forEach(item => {
|
||||
let result = {};
|
||||
result.actualResult = item.actualResult;
|
||||
result.executeResult = item.executeResult;
|
||||
param.results.push(result);
|
||||
});
|
||||
param.results = JSON.stringify(param.results);
|
||||
this.$post('/test/plan/case/edit', param, () => {
|
||||
this.$refs.drawer.closeDrawer();
|
||||
this.$message.success("保存成功!");
|
||||
this.$emit('refresh');
|
||||
});
|
||||
},
|
||||
handleNext() {
|
||||
this.index++;
|
||||
this.getTestCase(this.index);
|
||||
},
|
||||
handlePre() {
|
||||
this.index--;
|
||||
this.getTestCase(this.index);
|
||||
},
|
||||
getTestCase(index) {
|
||||
let testCase = this.tableData[index];
|
||||
let item = {};
|
||||
Object.assign(item, testCase);
|
||||
item.results = JSON.parse(item.results);
|
||||
item.steps = JSON.parse(item.steps);
|
||||
item.steptResults = [];
|
||||
for (let i = 0; i < item.steps.length; i++){
|
||||
if(item.results[i]){
|
||||
item.steps[i].actualResult = item.results[i].actualResult;
|
||||
item.steps[i].executeResult = item.results[i].executeResult;
|
||||
}
|
||||
item.steptResults.push(item.steps[i]);
|
||||
}
|
||||
this.testCase = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -173,10 +245,6 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.el-row {
|
||||
margin-bottom: 2%;
|
||||
}
|
||||
|
||||
.cast_label {
|
||||
color: dimgray;
|
||||
}
|
||||
|
@ -185,4 +253,24 @@
|
|||
padding-left: 4%;
|
||||
}
|
||||
|
||||
.head-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.el-col {
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.status-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.head-bar {
|
||||
margin-top: 1%;
|
||||
}
|
||||
|
||||
.head-right-tip {
|
||||
color: darkgrey;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
|
||||
<el-main class="main-content">
|
||||
<el-main>
|
||||
<el-card v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<div>
|
||||
|
@ -67,6 +67,24 @@
|
|||
<el-table-column
|
||||
prop="priority"
|
||||
:label="$t('test_track.priority')">
|
||||
<template v-slot:default="scope">
|
||||
<el-tag v-if="scope.row.priority == 'P0'"
|
||||
type="danger"
|
||||
effect="dark"
|
||||
size="mini">{{scope.row.priority}}</el-tag>
|
||||
<el-tag v-if="scope.row.priority == 'P1'"
|
||||
type="danger"
|
||||
effect="light"
|
||||
size="mini">{{scope.row.priority}}</el-tag>
|
||||
<el-tag v-if="scope.row.priority == 'P2'"
|
||||
type="warning"
|
||||
effect="dark"
|
||||
size="mini">{{scope.row.priority}}</el-tag>
|
||||
<el-tag v-if="scope.row.priority == 'P3'"
|
||||
type="warning"
|
||||
effect="light"
|
||||
size="mini">{{scope.row.priority}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
|
@ -101,7 +119,8 @@
|
|||
:label="$t('test_track.execute_result')">
|
||||
<template v-slot:default="scope">
|
||||
<el-tag v-if="scope.row.status == 'Prepare'"
|
||||
e ffect="info"
|
||||
type="info"
|
||||
effect="dark"
|
||||
size="mini">{{$t('test_track.plan_status_prepare')}}</el-tag>
|
||||
<el-tag v-if="scope.row.status == 'Pass'"
|
||||
type="success"
|
||||
|
@ -131,7 +150,7 @@
|
|||
<el-table-column
|
||||
:label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<el-button @click="handleEdit(scope.row)" type="primary" icon="el-icon-edit" size="mini" circle/>
|
||||
<el-button @click="handleEdit(scope.row, scope.$index)" type="primary" icon="el-icon-edit" size="mini" circle/>
|
||||
<el-button @click="handleDelete(scope.row)" type="danger" icon="el-icon-unlock" size="mini" circle/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -140,6 +159,11 @@
|
|||
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||
:total="total"/>
|
||||
|
||||
<test-plan-test-case-edit
|
||||
ref="testPlanTestCaseEdit"
|
||||
:table-data="tableData"
|
||||
@refresh="initTableData"/>
|
||||
|
||||
</el-card>
|
||||
</el-main>
|
||||
</template>
|
||||
|
@ -148,13 +172,14 @@
|
|||
import PlanNodeTree from './PlanNodeTree';
|
||||
import ExecutorEdit from './ExecutorEdit';
|
||||
import StatusEdit from './StatusEdit';
|
||||
import TestPlanTestCaseEdit from "../components/TestPlanTestCaseEdit";
|
||||
import MsTipButton from '../../../../components/common/components/MsTipButton';
|
||||
import MsTablePagination from '../../../../components/common/pagination/TablePagination';
|
||||
import {TokenKey} from '../../../../../common/js/constants';
|
||||
|
||||
export default {
|
||||
name: "TestPlanTestCaseList",
|
||||
components: {PlanNodeTree, StatusEdit, ExecutorEdit, MsTipButton, MsTablePagination},
|
||||
components: {PlanNodeTree, StatusEdit, ExecutorEdit, MsTipButton, MsTablePagination, TestPlanTestCaseEdit},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
|
@ -165,6 +190,7 @@
|
|||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
currentDataIndex: 0,
|
||||
selectIds: new Set(),
|
||||
}
|
||||
},
|
||||
|
@ -201,8 +227,11 @@
|
|||
buildPagePath(path) {
|
||||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||
},
|
||||
handleEdit(testCase) {
|
||||
this.$emit('editTestPlanTestCase', testCase);
|
||||
handleEdit(testCase, index) {
|
||||
this.currentDataIndex = index;
|
||||
this.$refs.testPlanTestCaseEdit.index = index;
|
||||
this.$refs.testPlanTestCaseEdit.getTestCase(index);
|
||||
this.$refs.testPlanTestCaseEdit.showDialog = true;
|
||||
},
|
||||
handleDelete(testCase) {
|
||||
this.$alert(this.$t('test_track.confirm_cancel_relevance') + ' ' + testCase.name + " ?", '', {
|
||||
|
|
Loading…
Reference in New Issue