diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.xml index 7b2f666cbf..fb99116be3 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.xml @@ -18,6 +18,7 @@ tplc.test_plan_id, tplc.load_case_id, lt.status, + tplc.status as caseStatus, lt.name as caseName, tplc.load_report_id, p.name as projectName diff --git a/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java b/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java index 5c20c0647e..db5be78c84 100644 --- a/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java +++ b/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java @@ -47,7 +47,7 @@ public class PerformanceNoticeTask { if (StringUtils.equalsAny(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Completed.name(), PerformanceTestStatus.Error.name())) { sendNotice(loadTestReportFromDatabase); - isRunning = false; + return; } try { //查询定时任务是否关闭 diff --git a/backend/src/main/java/io/metersphere/track/controller/TestPlanLoadCaseController.java b/backend/src/main/java/io/metersphere/track/controller/TestPlanLoadCaseController.java index ab1730626c..3f1fa405a6 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestPlanLoadCaseController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestPlanLoadCaseController.java @@ -3,6 +3,7 @@ package io.metersphere.track.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.base.domain.LoadTest; +import io.metersphere.base.domain.TestPlanLoadCase; import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.track.dto.TestPlanLoadCaseDTO; @@ -57,4 +58,9 @@ public class TestPlanLoadCaseController { public void batchDelete(@RequestBody List ids) { testPlanLoadCaseService.batchDelete(ids); } + + @PostMapping("/update") + public void update(@RequestBody TestPlanLoadCase testPlanLoadCase) { + testPlanLoadCaseService.update(testPlanLoadCase); + } } diff --git a/backend/src/main/java/io/metersphere/track/dto/TestPlanLoadCaseDTO.java b/backend/src/main/java/io/metersphere/track/dto/TestPlanLoadCaseDTO.java index 572532baf0..6dcfd166ab 100644 --- a/backend/src/main/java/io/metersphere/track/dto/TestPlanLoadCaseDTO.java +++ b/backend/src/main/java/io/metersphere/track/dto/TestPlanLoadCaseDTO.java @@ -10,4 +10,5 @@ public class TestPlanLoadCaseDTO extends TestPlanLoadCase { private String userName; private String caseName; private String projectName; + private String caseStatus; } diff --git a/backend/src/main/java/io/metersphere/track/service/LoadReportStatusTask.java b/backend/src/main/java/io/metersphere/track/service/LoadReportStatusTask.java new file mode 100644 index 0000000000..17a9daab64 --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/service/LoadReportStatusTask.java @@ -0,0 +1,66 @@ +package io.metersphere.track.service; + +import io.metersphere.base.domain.LoadTestReportWithBLOBs; +import io.metersphere.base.domain.TestPlanLoadCase; +import io.metersphere.base.mapper.LoadTestReportMapper; +import io.metersphere.base.mapper.TestPlanLoadCaseMapper; +import io.metersphere.commons.constants.PerformanceTestStatus; +import io.metersphere.commons.utils.LogUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Component +public class LoadReportStatusTask { + @Resource + private LoadTestReportMapper loadTestReportMapper; + @Resource + private TestPlanLoadCaseMapper testPlanLoadCaseMapper; + + private final ExecutorService executorService = Executors.newFixedThreadPool(20); + + private boolean isRunning = false; + + @PreDestroy + public void preDestroy() { + isRunning = false; + } + + public void registerReportIsEndTask(String id, String reportId) { + isRunning = true; + // todo 手动创建线程池 + executorService.submit(() -> { + while (isRunning) { + LoadTestReportWithBLOBs report = loadTestReportMapper.selectByPrimaryKey(reportId); + if (StringUtils.equalsAny(report.getStatus(), PerformanceTestStatus.Completed.name(), PerformanceTestStatus.Error.name())) { + updateLoadCaseStatus(id, report.getStatus()); + return; + } + try { + //查询定时任务是否关闭 + Thread.sleep(1000 * 10);// 检查 loadtest 的状态 + } catch (InterruptedException e) { + LogUtil.error(e.getMessage(), e); + } + } + }); + } + + private void updateLoadCaseStatus(String testPlanLoadCaseId, String status) { + TestPlanLoadCase testPlanLoadCase = new TestPlanLoadCase(); + testPlanLoadCase.setId(testPlanLoadCaseId); + String result = ""; + if (StringUtils.equals(PerformanceTestStatus.Error.name(), status)) { + result = "error"; + } + if (StringUtils.equals(PerformanceTestStatus.Completed.name(), status)) { + result = "success"; + } + testPlanLoadCase.setStatus(result); + testPlanLoadCaseMapper.updateByPrimaryKeySelective(testPlanLoadCase); + } +} diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanLoadCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanLoadCaseService.java index f300203be7..3dd1a644d3 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanLoadCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanLoadCaseService.java @@ -16,6 +16,7 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.util.ArrayList; @@ -39,6 +40,8 @@ public class TestPlanLoadCaseService { private LoadTestReportMapper loadTestReportMapper; @Resource private LoadTestMapper loadTestMapper; + @Resource + private LoadReportStatusTask loadReportStatusTask; public List relevanceList(LoadCaseRequest request) { List ids = extTestPlanLoadCaseMapper.selectIdsNotInPlan(request.getProjectId(), request.getTestPlanId()); @@ -82,6 +85,7 @@ public class TestPlanLoadCaseService { testPlanLoadCase.setId(request.getTestPlanLoadId()); testPlanLoadCase.setLoadReportId(reportId); testPlanLoadCaseMapper.updateByPrimaryKeySelective(testPlanLoadCase); + loadReportStatusTask.registerReportIsEndTask(request.getTestPlanLoadId(), reportId); return reportId; } @@ -122,4 +126,10 @@ public class TestPlanLoadCaseService { example.createCriteria().andIdIn(ids); testPlanLoadCaseMapper.deleteByExample(example); } + + public void update(TestPlanLoadCase testPlanLoadCase) { + if (!StringUtils.isEmpty(testPlanLoadCase.getId())) { + testPlanLoadCaseMapper.updateByPrimaryKeySelective(testPlanLoadCase); + } + } } diff --git a/frontend/src/business/components/common/components/MsTableOperator.vue b/frontend/src/business/components/common/components/MsTableOperator.vue index 0da52f1145..7477ba8c3a 100644 --- a/frontend/src/business/components/common/components/MsTableOperator.vue +++ b/frontend/src/business/components/common/components/MsTableOperator.vue @@ -4,7 +4,7 @@ - + diff --git a/frontend/src/business/components/track/plan/view/comonents/load/TestPlanLoadCaseList.vue b/frontend/src/business/components/track/plan/view/comonents/load/TestPlanLoadCaseList.vue index 027a0ef270..b6f39381f9 100644 --- a/frontend/src/business/components/track/plan/view/comonents/load/TestPlanLoadCaseList.vue +++ b/frontend/src/business/components/track/plan/view/comonents/load/TestPlanLoadCaseList.vue @@ -65,6 +65,19 @@ + + + @@ -187,6 +200,7 @@ export default { if (arr.length > 0) { this.initTable(); } else { + setTimeout(this.initTable, 3000); clearInterval(this.refreshScheduler); } }, 4000); @@ -233,10 +247,15 @@ export default { }, handleRunBatch() { this.selectRows.forEach(loadCase => { - this.run(loadCase); + this._run(loadCase); }) + this.refreshStatus(); }, run(loadCase) { + this._run(loadCase); + this.refreshStatus(); + }, + _run(loadCase) { this.$post('/test/plan/load/case/run', { id: loadCase.loadCaseId, testPlanLoadId: loadCase.id, @@ -249,12 +268,15 @@ export default { }); this.initTable(); }).catch(() => { + //todo 用例出错 + this.$post('/test/plan/load/case/update', {id: loadCase.id, status: "error"},() => { + this.initTable(); + }); this.$notify.error({ title: loadCase.caseName, message: '用例执行错误,请单独调试该用例!' }); }) - this.refreshStatus(); }, handleDelete(loadCase) { this.result = this.$get('/test/plan/load/case/delete/' + loadCase.id, () => {