refactor(测试用例): 用例导出优化

This commit is contained in:
WangXu10 2024-08-08 18:14:19 +08:00 committed by Craftsman
parent c2108ecc15
commit 3f91e67ed7
11 changed files with 110 additions and 36 deletions

View File

@ -0,0 +1,7 @@
-- set innodb lock wait timeout
SET SESSION innodb_lock_wait_timeout = 7200;
-- 项目管理员、项目成员增加权限
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'FUNCTIONAL_CASE:READ+EXPORT');
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'FUNCTIONAL_CASE:READ+EXPORT');

View File

@ -28,7 +28,12 @@ public class ExportMsgDTO implements Serializable {
*/
private int count;
/**
* 消息类型LINK-链接标识HEARTBEAT-心跳检查标识EXEC_START-开始执行标识EXEC_RESULT-执行结果标识
* 导出状态
*/
private boolean isSuccessful;
/**
* 消息类型CONNECT-链接标识HEARTBEAT-心跳检查标识EXEC_START-开始执行标识EXEC_RESULT-执行结果标识
*/
private String msgType;
}

View File

@ -4,6 +4,7 @@ import com.alibaba.excel.util.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.dto.ExportTaskDTO;
import io.metersphere.functional.dto.FunctionalCaseDetailDTO;
import io.metersphere.functional.dto.FunctionalCasePageDTO;
import io.metersphere.functional.dto.FunctionalCaseVersionDTO;
@ -272,8 +273,8 @@ public class FunctionalCaseController {
@PostMapping("/export/excel")
@Operation(summary = "用例管理-功能用例-excel导出")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_EXPORT)
public void testCaseExport(@Validated @RequestBody FunctionalCaseExportRequest request) {
functionalCaseFileService.export(SessionUtils.getUserId(), request);
public String testCaseExport(@Validated @RequestBody FunctionalCaseExportRequest request) {
return functionalCaseFileService.export(SessionUtils.getUserId(), request);
}
@GetMapping("/stop/{taskId}")
@ -312,14 +313,14 @@ public class FunctionalCaseController {
@PostMapping("/export/xmind")
@Operation(summary = "用例管理-功能用例-xmind导出")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_EXPORT)
public void caseExportXmind(@Validated @RequestBody FunctionalCaseExportRequest request) {
functionalCaseXmindService.exportFunctionalCaseXmind(request, SessionUtils.getUserId());
public String caseExportXmind(@Validated @RequestBody FunctionalCaseExportRequest request) {
return functionalCaseXmindService.exportFunctionalCaseXmind(request, SessionUtils.getUserId());
}
@GetMapping(value = "/check/export-task")
@Operation(summary = "用例管理-功能用例-导出任务校验")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_EXPORT)
public String checkExportTask() {
public ExportTaskDTO checkExportTask() {
return functionalCaseFileService.checkExportTask(SessionUtils.getCurrentProjectId(), SessionUtils.getUserId());
}
}

View File

@ -0,0 +1,22 @@
package io.metersphere.functional.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author wx
*/
@Data
public class ExportTaskDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "文件id")
private String fileId;
@Schema(description = "任务id")
private String taskId;
}

View File

@ -10,6 +10,7 @@ import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import io.metersphere.functional.constants.FunctionalCaseTypeConstants;
import io.metersphere.functional.domain.*;
import io.metersphere.functional.dto.ExportTaskDTO;
import io.metersphere.functional.dto.response.FunctionalCaseImportResponse;
import io.metersphere.functional.excel.constants.FunctionalCaseImportFiled;
import io.metersphere.functional.excel.converter.FunctionalCaseExportConverter;
@ -298,7 +299,7 @@ public class FunctionalCaseFileService {
*
* @return FunctionalCaseImportResponse
*/
public FunctionalCaseImportResponse preCheckXMind(FunctionalCaseImportRequest request,SessionUser user, MultipartFile multipartFile) {
public FunctionalCaseImportResponse preCheckXMind(FunctionalCaseImportRequest request, SessionUser user, MultipartFile multipartFile) {
if (multipartFile == null) {
throw new MSException(Translator.get("file_cannot_be_null"));
}
@ -313,11 +314,11 @@ public class FunctionalCaseFileService {
Long lasePos = nextPos + ((long) ServiceUtils.POS_STEP * Integer.parseInt(request.getCount()));
//获取当前项目默认模板的自定义字段
List<TemplateCustomFieldDTO> customFields = getCustomFields(request.getProjectId());
XMindCaseParser xMindParser = new XMindCaseParser(request, customFields, user,lasePos);
XMindCaseParser xMindParser = new XMindCaseParser(request, customFields, user, lasePos);
errList = xMindParser.parse(multipartFile);
xMindParser.clear();
response.setErrorMessages(errList);
response.setSuccessCount(xMindParser.getList().size()+xMindParser.getUpdateList().size());
response.setSuccessCount(xMindParser.getList().size() + xMindParser.getUpdateList().size());
response.setFailCount(errList.size());
return response;
} catch (Exception e) {
@ -381,7 +382,7 @@ public class FunctionalCaseFileService {
Long lasePos = nextPos + ((long) ServiceUtils.POS_STEP * Integer.parseInt(request.getCount()));
//获取当前项目默认模板的自定义字段
List<TemplateCustomFieldDTO> customFields = getCustomFields(request.getProjectId());
XMindCaseParser xmindParser = new XMindCaseParser(request, customFields, user,lasePos);
XMindCaseParser xmindParser = new XMindCaseParser(request, customFields, user, lasePos);
errList = xmindParser.parse(multipartFile);
if (CollectionUtils.isEmpty(xmindParser.getList())
&& CollectionUtils.isEmpty(xmindParser.getUpdateList())) {
@ -394,7 +395,7 @@ public class FunctionalCaseFileService {
xmindParser.saveData();
xmindParser.clear();
response.setErrorMessages(errList);
response.setSuccessCount(xmindParser.getList().size()+xmindParser.getUpdateList().size());
response.setSuccessCount(xmindParser.getList().size() + xmindParser.getUpdateList().size());
response.setFailCount(errList.size());
return response;
} catch (Exception e) {
@ -403,21 +404,24 @@ public class FunctionalCaseFileService {
}
}
public void export(String userId, FunctionalCaseExportRequest request) {
public String export(String userId, FunctionalCaseExportRequest request) {
try {
ExportTaskExample exportTaskExample = new ExportTaskExample();
exportTaskExample.createCriteria().andTypeEqualTo(ExportConstants.ExportType.CASE.toString()).andStateEqualTo(ExportConstants.ExportState.PREPARED.toString());
long preparedCount = exportTaskMapper.countByExample(exportTaskExample);
if (preparedCount > 0) {
throw new MSException(Translator.get("export_case_task_existed"));
}
exportTaskManager.exportAsyncTask(request.getProjectId(), request.getFileId(), userId, ExportConstants.ExportType.CASE.toString(), request, t -> exportFunctionalCaseZip(request, userId));
exportCheck(request, userId);
ExportTask exportTask = exportTaskManager.exportAsyncTask(request.getProjectId(), request.getFileId(), userId, ExportConstants.ExportType.CASE.toString(), request, t -> exportFunctionalCaseZip(request, userId));
return exportTask.getId();
} catch (InterruptedException e) {
LogUtils.error("导出失败:" + e);
throw new MSException(e);
}
}
public void exportCheck(FunctionalCaseExportRequest request, String userId) {
List<ExportTask> exportTasks = getExportTasks(request.getProjectId(), userId);
if (CollectionUtils.isNotEmpty(exportTasks)) {
throw new MSException(Translator.get("export_case_task_existed"));
}
}
/**
* 导出excel
@ -462,9 +466,11 @@ public class FunctionalCaseFileService {
} else {
taskId = MsgType.CONNECT.name();
}
ExportMsgDTO exportMsgDTO = new ExportMsgDTO(request.getFileId(), taskId, ids.size(), MsgType.CONNECT.name());
ExportMsgDTO exportMsgDTO = new ExportMsgDTO(request.getFileId(), taskId, ids.size(), true, MsgType.EXEC_RESULT.name());
ExportWebSocketHandler.sendMessageSingle(exportMsgDTO);
} catch (Exception e) {
ExportMsgDTO exportMsgDTO = new ExportMsgDTO(request.getFileId(), "", 0, false, MsgType.EXEC_RESULT.name());
ExportWebSocketHandler.sendMessageSingle(exportMsgDTO);
List<ExportTask> exportTasks = getExportTasks(request.getProjectId(), userId);
if (CollectionUtils.isNotEmpty(exportTasks)) {
updateExportTask(ExportConstants.ExportState.ERROR.name(), exportTasks.getFirst().getId(), fileType);
@ -862,7 +868,7 @@ public class FunctionalCaseFileService {
public ResponseEntity<byte[]> downloadFile(String projectId, String fileId, String userId) {
List<ExportTask> exportTasks = getExportTasksByFileId(projectId, userId, fileId);
if (CollectionUtils.isEmpty(exportTasks)) {
throw new MSException("任务不存在");
return ResponseEntity.notFound().build();
}
ExportTask tasksFirst = exportTasks.getFirst();
Project project = projectMapper.selectByPrimaryKey(projectId);
@ -900,12 +906,15 @@ public class FunctionalCaseFileService {
exportTaskManager.sendStopMessage(taskId, userId);
}
public String checkExportTask(String projectId, String userId) {
public ExportTaskDTO checkExportTask(String projectId, String userId) {
ExportTaskDTO exportTaskDTO = new ExportTaskDTO();
List<ExportTask> exportTasks = getExportTasks(projectId, userId);
if (CollectionUtils.isNotEmpty(exportTasks)) {
return exportTasks.getFirst().getFileId();
exportTaskDTO.setFileId(exportTasks.getFirst().getFileId());
exportTaskDTO.setTaskId(exportTasks.getFirst().getId());
return exportTaskDTO;
} else {
return StringUtils.EMPTY;
return exportTaskDTO;
}
}
}

View File

@ -95,9 +95,11 @@ public class FunctionalCaseXmindService {
*
* @param request
*/
public void exportFunctionalCaseXmind(FunctionalCaseExportRequest request, String userId) {
public String exportFunctionalCaseXmind(FunctionalCaseExportRequest request, String userId) {
try {
exportTaskManager.exportAsyncTask(request.getProjectId(), request.getFileId(), userId, ExportConstants.ExportType.CASE.toString(), request, t -> exportXmind(request, userId));
functionalCaseFileService.exportCheck(request, userId);
ExportTask exportTask = exportTaskManager.exportAsyncTask(request.getProjectId(), request.getFileId(), userId, ExportConstants.ExportType.CASE.toString(), request, t -> exportXmind(request, userId));
return exportTask.getId();
} catch (InterruptedException e) {
LogUtils.error("导出失败:" + e);
throw new MSException(e);
@ -130,9 +132,11 @@ public class FunctionalCaseXmindService {
} else {
taskId = MsgType.CONNECT.name();
}
ExportMsgDTO exportMsgDTO = new ExportMsgDTO(request.getFileId(), taskId, ids.size(), MsgType.CONNECT.name());
ExportMsgDTO exportMsgDTO = new ExportMsgDTO(request.getFileId(), taskId, ids.size(), true, MsgType.EXEC_RESULT.name());
ExportWebSocketHandler.sendMessageSingle(exportMsgDTO);
} catch (Exception e) {
ExportMsgDTO exportMsgDTO = new ExportMsgDTO(request.getFileId(), "", 0, false, MsgType.EXEC_RESULT.name());
ExportWebSocketHandler.sendMessageSingle(exportMsgDTO);
List<ExportTask> exportTasks = functionalCaseFileService.getExportTasks(request.getProjectId(), userId);
if (CollectionUtils.isNotEmpty(exportTasks)) {
functionalCaseFileService.updateExportTask(ExportConstants.ExportState.ERROR.name(), exportTasks.getFirst().getId(), XMIND);

View File

@ -49,7 +49,7 @@ public class ExportWebSocketHandler {
ONLINE_EXPORT_EXCEL_SESSIONS.put(fileId, session);
RemoteEndpoint.Async async = session.getAsyncRemote();
if (async != null) {
async.sendText(JSON.toJSONString(new ExportMsgDTO(fileId, "", 0, MsgType.CONNECT.name())));
async.sendText(JSON.toJSONString(new ExportMsgDTO(fileId, "", 0, true, MsgType.CONNECT.name())));
session.setMaxIdleTimeout(180000);
}
LogUtils.info("客户端: [" + fileId + "] : 连接成功!" + ExportWebSocketHandler.ONLINE_EXPORT_EXCEL_SESSIONS.size(), fileId);
@ -92,7 +92,7 @@ public class ExportWebSocketHandler {
@Scheduled(fixedRate = 60000)
public void heartbeatCheck() {
ExportWebSocketHandler.sendMessageSingle(
new ExportMsgDTO(MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), 0, "heartbeat check")
new ExportMsgDTO(MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), 0, true, MsgType.HEARTBEAT.name())
);
}
}

View File

@ -173,7 +173,7 @@ public class XmindExportUtil {
//文本描述
ITopic textDesTopic = workbook.createTopic();
String desc = dto.getTextDescription();
textDesTopic.setTitleText(desc == null ? Translator.get("xmind_textDescription").concat(": ") : Translator.get("xmind_textDescription").concat(": ").concat(Translator.get("xmind_textDescription")).concat(": ").concat(desc));
textDesTopic.setTitleText(desc == null ? Translator.get("xmind_textDescription").concat(": ") : Translator.get("xmind_textDescription").concat(": ").concat(desc));
if (style != null) {
textDesTopic.setStyleId(style.getId());
}

View File

@ -28,6 +28,9 @@
{
"id": "FUNCTIONAL_CASE:READ+IMPORT"
},
{
"id": "FUNCTIONAL_CASE:READ+EXPORT"
},
{
"id": "FUNCTIONAL_CASE:READ+MINDER",
"name": "permission.functional_case.minder"

View File

@ -6,6 +6,7 @@ import io.metersphere.functional.dto.FunctionalCaseAttachmentDTO;
import io.metersphere.functional.dto.FunctionalCasePageDTO;
import io.metersphere.functional.dto.response.FunctionalCaseImportResponse;
import io.metersphere.functional.excel.domain.FunctionalCaseHeader;
import io.metersphere.functional.mapper.ExportTaskMapper;
import io.metersphere.functional.mapper.FunctionalCaseAttachmentMapper;
import io.metersphere.functional.mapper.FunctionalCaseCustomFieldMapper;
import io.metersphere.functional.mapper.FunctionalCaseMapper;
@ -113,6 +114,8 @@ public class FunctionalCaseControllerTests extends BaseTest {
private FunctionalCaseMapper functionalCaseMapper;
protected static String functionalCaseId;
@Resource
private ExportTaskMapper exportTaskMapper;
@Test
@ -990,11 +993,30 @@ public class FunctionalCaseControllerTests extends BaseTest {
@Test
@Order(24)
public void downloadFile() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get(DOWNLOAD_FILE_URL + DEFAULT_PROJECT_ID + "/" + "123142342")
download("12222");
ExportTask exportTask = new ExportTask();
exportTask.setId("12314234222");
exportTask.setProjectId(DEFAULT_PROJECT_ID);
exportTask.setFileId("123142342");
exportTask.setFileType("xlsx");
exportTask.setType("CASE");
exportTask.setState("SUCCESS");
exportTask.setCreateTime(System.currentTimeMillis());
exportTask.setCreateUser("admin");
exportTask.setUpdateUser("admin");
exportTask.setUpdateTime(System.currentTimeMillis());
exportTaskMapper.insertSelective(exportTask);
download("123142342");
}
private void download(String fileId) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get(DOWNLOAD_FILE_URL + DEFAULT_PROJECT_ID + "/" + fileId)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken));
}
@Test
@Order(25)
public void stopExport() throws Exception {
@ -1033,7 +1055,7 @@ public class FunctionalCaseControllerTests extends BaseTest {
}};
request.setOtherFields(otherHeaders);
request.setFileId("123142342");
request.setFileId("1231423421");
this.requestPost(EXPORT_XMIND_URL, request);
request.setSelectIds(new ArrayList<>());
this.requestPost(EXPORT_XMIND_URL, request);
@ -1044,7 +1066,7 @@ public class FunctionalCaseControllerTests extends BaseTest {
@Test
@Order(4)
public void checkExportTask() throws Exception {
this.requestGetExcel( EXPORT_XMIND_CHECK_URL);
this.requestGetExcel(EXPORT_XMIND_CHECK_URL);
}
}

View File

@ -34,7 +34,7 @@ public class ExportTaskManager {
public static final String EXPORT_CONSUME = "export_consume";
public <T> void exportAsyncTask(String projectId, String fileId, String userId, String type, T t, Function<Object, Object> selectListFunc) throws InterruptedException {
public <T> ExportTask exportAsyncTask(String projectId, String fileId, String userId, String type, T t, Function<Object, Object> selectListFunc) throws InterruptedException {
ExportTask exportTask = buildExportTask(projectId, fileId, userId, type);
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<?> future = executorService.submit(() -> {
@ -46,9 +46,10 @@ public class ExportTaskManager {
LogUtils.info("Thread has been interrupted.");
});
map.put(exportTask.getId(), future);
return exportTask;
}
private ExportTask buildExportTask(String projectId, String fileId, String userId, String type) {
public ExportTask buildExportTask(String projectId, String fileId, String userId, String type) {
ExportTask exportTask = new ExportTask();
exportTask.setId(IDGenerator.nextStr());
exportTask.setType(type);
@ -59,7 +60,7 @@ public class ExportTaskManager {
exportTask.setUpdateTime(System.currentTimeMillis());
exportTask.setProjectId(projectId);
exportTask.setFileType(fileId);
exportTaskMapper.insert(exportTask);
exportTaskMapper.insertSelective(exportTask);
return exportTask;
}