提交 0c932748 authored 作者: 黄夏豪's avatar 黄夏豪

fix(base): 修了很多Bug

上级 811fbcd4
...@@ -157,7 +157,7 @@ CREATE TABLE `kt_execution_record` ( ...@@ -157,7 +157,7 @@ CREATE TABLE `kt_execution_record` (
`test_data_id` bigint(20) DEFAULT NULL COMMENT '测试数据id', `test_data_id` bigint(20) DEFAULT NULL COMMENT '测试数据id',
`status` int(11) DEFAULT NULL COMMENT '执行状态,0:停止,1:执行', `status` int(11) DEFAULT NULL COMMENT '执行状态,0:停止,1:执行',
`type` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '类型', `type` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '类型',
`union_key` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT 'key用来记录执行批次', `unique_key` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT 'key用来记录执行批次',
`log` text CHARACTER SET utf8 DEFAULT NULL COMMENT '日志', `log` text CHARACTER SET utf8 DEFAULT NULL COMMENT '日志',
`create_time` timestamp NULL DEFAULT NULL, `create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL, `update_time` timestamp NULL DEFAULT NULL,
......
...@@ -81,7 +81,7 @@ create table kt_execution_record ...@@ -81,7 +81,7 @@ create table kt_execution_record
test_data_id bigint null comment '测试数据id', test_data_id bigint null comment '测试数据id',
status int null comment '执行状态,0:停止,1:执行', status int null comment '执行状态,0:停止,1:执行',
type varchar(255) charset utf8 null comment '类型', type varchar(255) charset utf8 null comment '类型',
union_key varchar(255) charset utf8 null comment 'key用来记录执行批次', unique_key varchar(255) charset utf8 null comment 'key用来记录执行批次',
log text charset utf8 null comment '日志', log text charset utf8 null comment '日志',
create_time timestamp not null comment '数据创建时间', create_time timestamp not null comment '数据创建时间',
update_time timestamp not null comment '数据更新时间' update_time timestamp not null comment '数据更新时间'
......
...@@ -30,10 +30,8 @@ import java.io.IOException; ...@@ -30,10 +30,8 @@ import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -62,9 +60,9 @@ public class HttpClientActuator implements Actuator { ...@@ -62,9 +60,9 @@ public class HttpClientActuator implements Actuator {
private void completeHttpRequestDetail(HttpRequestDetail httpRequestDetail,Long envId,Long projectId){ private void completeHttpRequestDetail(HttpRequestDetail httpRequestDetail,Long envId,Long projectId){
for (RequestHeader header : httpRequestDetail.getHeaders()) { for (RequestHeader header : httpRequestDetail.getHeaders()) {
//获取动态变量,并将动态变量替换进去 //获取动态变量,并将动态变量替换进去
header.setName( header.setKey(
completeExpressionUtil.completeDynamicVariable( completeExpressionUtil.completeDynamicVariable(
header.getName(), header.getKey(),
envId, envId,
projectId) projectId)
); );
......
...@@ -13,11 +13,11 @@ import org.apache.http.message.BasicHeader; ...@@ -13,11 +13,11 @@ import org.apache.http.message.BasicHeader;
@NoArgsConstructor @NoArgsConstructor
public class RequestHeader { public class RequestHeader {
private String name; private String key;
private String value; private String value;
public BasicHeader getBasicHeader(){ public BasicHeader getBasicHeader(){
return new BasicHeader(name,value); return new BasicHeader(key,value);
} }
} }
...@@ -2,6 +2,7 @@ package org.matrix.actuators.usecase; ...@@ -2,6 +2,7 @@ package org.matrix.actuators.usecase;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.matrix.actuators.Actuator; import org.matrix.actuators.Actuator;
...@@ -18,20 +19,20 @@ import org.matrix.actuators.httpclient.HttpResponseDetail; ...@@ -18,20 +19,20 @@ import org.matrix.actuators.httpclient.HttpResponseDetail;
import org.matrix.database.service.IExecutionHistoryService; import org.matrix.database.service.IExecutionHistoryService;
import org.matrix.enums.ExecutionHistoryStatus; import org.matrix.enums.ExecutionHistoryStatus;
import org.matrix.exception.GlobalException; import org.matrix.exception.GlobalException;
import org.matrix.socket.ExecutionStatusMonitorSocketHandler;
import org.matrix.socket.pool.TestCaseExecuteSocketPool; import org.matrix.socket.pool.TestCaseExecuteSocketPool;
import org.matrix.socket.queue.LogQueueRuntime; import org.matrix.socket.queue.LogQueueRuntime;
import org.matrix.socket.vo.CaseExecuteVo; import org.matrix.socket.vo.CaseExecuteVo;
import org.matrix.socket.vo.TestExecuteLog; import org.matrix.socket.vo.TestExecuteLog;
import org.matrix.util.SpringUtils; import org.matrix.util.SpringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.UUID;
/** /**
* 测试用例执行器 * 测试用例执行器
...@@ -48,10 +49,13 @@ public class CaseActuator implements Actuator { ...@@ -48,10 +49,13 @@ public class CaseActuator implements Actuator {
private final String baseJsPath = "syntaxCheck.js"; private final String baseJsPath = "syntaxCheck.js";
public CaseActuator(CheckPointActuator checkPointActuator, HttpClientActuator httpClientActuator, IExecutionHistoryService executionHistoryService) { private final ExecutionStatusMonitorSocketHandler executionStatusMonitorSocketHandler;
public CaseActuator(CheckPointActuator checkPointActuator, HttpClientActuator httpClientActuator, IExecutionHistoryService executionHistoryService, ExecutionStatusMonitorSocketHandler executionStatusMonitorSocketHandler) {
this.checkPointActuator = checkPointActuator; this.checkPointActuator = checkPointActuator;
this.httpClientActuator = httpClientActuator; this.httpClientActuator = httpClientActuator;
this.executionHistoryService = executionHistoryService; this.executionHistoryService = executionHistoryService;
this.executionStatusMonitorSocketHandler = executionStatusMonitorSocketHandler;
} }
...@@ -221,7 +225,9 @@ public class CaseActuator implements Actuator { ...@@ -221,7 +225,9 @@ public class CaseActuator implements Actuator {
* @param session 如果是从socket运行并希望获取实时日志请从这里运行 * @param session 如果是从socket运行并希望获取实时日志请从这里运行
* 外界如果执行测试用例的话请走这个接口,执行TestCase,并控制运行态日志池,进行日志的生成。 * 外界如果执行测试用例的话请走这个接口,执行TestCase,并控制运行态日志池,进行日志的生成。
*/ */
public List<TestCaseExecuteResult> runTestCase(WebSocketSession session, CaseExecuteVo caseExecuteVo) { public RunCaseResult runTestCase(WebSocketSession session, CaseExecuteVo caseExecuteVo) {
RunCaseResult runCaseResult = new RunCaseResult();
runCaseResult.setJobId(caseExecuteVo.getJobId());
String uniqueKey = UUID.randomUUID().toString(); String uniqueKey = UUID.randomUUID().toString();
Long currentThreadId = ThreadUtil.currentThreadId(); Long currentThreadId = ThreadUtil.currentThreadId();
try { try {
...@@ -236,6 +242,7 @@ public class CaseActuator implements Actuator { ...@@ -236,6 +242,7 @@ public class CaseActuator implements Actuator {
} }
//建立执行历史(ExecutionHistory) //建立执行历史(ExecutionHistory)
insertExecutionHistory(uniqueKey, caseExecuteVo); insertExecutionHistory(uniqueKey, caseExecuteVo);
Map<Long,List<TestCaseExecuteResult>> resultMap= new HashMap<>();
for (TestCaseListDataBto testCaseListDataBto : testCaseListDataBtoList) { for (TestCaseListDataBto testCaseListDataBto : testCaseListDataBtoList) {
LogQueueRuntime LogQueueRuntime
.initTestCaseLog( .initTestCaseLog(
...@@ -246,7 +253,11 @@ public class CaseActuator implements Actuator { ...@@ -246,7 +253,11 @@ public class CaseActuator implements Actuator {
, uniqueKey , uniqueKey
); );
//执行测试用例 //执行测试用例
return executeTestCases(testCaseListDataBto, caseExecuteVo.getEnvId(), caseExecuteVo.getProjectId()); if (testCaseListDataBto.getTestDataList()!=null&&testCaseListDataBto.getTestDataList().size()>0){
List<TestCaseExecuteResult> resultList = executeTestCases(testCaseListDataBto, caseExecuteVo.getEnvId(), caseExecuteVo.getProjectId());
resultMap.put(testCaseListDataBto.getTestCase().getId(),resultList);
runCaseResult.setExecutionMap(resultMap);
}
} }
} catch (GlobalException e) { } catch (GlobalException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -344,28 +355,58 @@ public class CaseActuator implements Actuator { ...@@ -344,28 +355,58 @@ public class CaseActuator implements Actuator {
.eq(ExecutionHistory::getDataId,currentTestExecute.getTestDataId()) .eq(ExecutionHistory::getDataId,currentTestExecute.getTestDataId())
.eq(ExecutionHistory::getUniqueKey,currentTestExecute.getUniqueKey()) .eq(ExecutionHistory::getUniqueKey,currentTestExecute.getUniqueKey())
.eq(ExecutionHistory::getUserId,currentTestExecute.getUserId()) .eq(ExecutionHistory::getUserId,currentTestExecute.getUserId())
); );
//发送执行状态
try {
executionStatusMonitorSocketHandler.sendOverviewCurrentStatus(currentTestExecute.getUniqueKey());
executionStatusMonitorSocketHandler.sendDetailCurrentStatus(
currentTestExecute.getUserId(),
currentTestExecute.getTestJobId(),
currentTestExecute.getTestCaseId(),
currentTestExecute.getTestDataId(),
currentTestExecute.getUniqueKey(),
executionHistoryStatus);
} catch (IOException e) {
e.printStackTrace();
}
} }
} }
/** /**
* 将所有还未完成的执行历史设置为ERROR * 将所有还未完成的执行历史设置为ERROR
*/ */
public void endExecutionHistory() { public void endExecutionHistory() {
TestExecuteLog currentTestExecute = LogQueueRuntime.getCurrentTestExecute(ThreadUtil.currentThreadId()); TestExecuteLog currentTestExecute = LogQueueRuntime.getCurrentTestExecute(ThreadUtil.currentThreadId());
if (currentTestExecute!=null){ if (currentTestExecute!=null){
LambdaUpdateWrapper<ExecutionHistory> wrapper = Wrappers
.lambdaUpdate(ExecutionHistory.class)
.eq(ExecutionHistory::getJobId, currentTestExecute.getTestJobId())
.eq(ExecutionHistory::getCaseId, currentTestExecute.getTestCaseId())
.eq(ExecutionHistory::getUniqueKey, currentTestExecute.getUniqueKey())
.eq(ExecutionHistory::getUserId, currentTestExecute.getUserId())
.ne(ExecutionHistory::getStatus, ExecutionHistoryStatus.FINISH);
ExecutionHistory executionHistory = new ExecutionHistory(); ExecutionHistory executionHistory = new ExecutionHistory();
executionHistory.setStatus(ExecutionHistoryStatus.ERROR); executionHistory.setStatus(ExecutionHistoryStatus.ERROR);
executionHistory.setEndTime(LocalDateTime.now()); executionHistory.setEndTime(LocalDateTime.now());
executionHistoryService.update(executionHistory, Wrappers List<ExecutionHistory> list = executionHistoryService.list(wrapper);
.lambdaUpdate(ExecutionHistory.class) executionHistoryService.update(executionHistory, wrapper);
.eq(ExecutionHistory::getJobId,currentTestExecute.getTestJobId()) try {
.eq(ExecutionHistory::getCaseId,currentTestExecute.getTestCaseId()) executionStatusMonitorSocketHandler.sendOverviewCurrentStatus(currentTestExecute.getUniqueKey());
.eq(ExecutionHistory::getUniqueKey,currentTestExecute.getUniqueKey()) for (ExecutionHistory history : list) {
.eq(ExecutionHistory::getUserId,currentTestExecute.getUserId()) executionStatusMonitorSocketHandler.sendDetailCurrentStatus(
.ne(ExecutionHistory::getStatus,ExecutionHistoryStatus.FINISH) history.getUserId(),
); history.getJobId(),
history.getCaseId(),
history.getDataId(),
history.getUniqueKey(),
ExecutionHistoryStatus.ERROR);
}
} catch (IOException e) {
e.printStackTrace();
}
} }
} }
......
package org.matrix.actuators.usecase;
import lombok.Data;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 当用户执行了一组测试用例后,会返回这个对象
* @author huangxiahao
*/
@Data
public class RunCaseResult {
private Long jobId;
/**
* Key为caseId,List为case下的每一个执行结果
*/
private Map<Long, List<TestCaseExecuteResult>> executionMap= new HashMap<>();
}
package org.matrix.config; package org.matrix.config;
import org.matrix.socket.ExecutionSocketHandler; import org.matrix.socket.ExecutionSocketHandler;
import org.springframework.beans.factory.annotation.Autowired; import org.matrix.socket.ExecutionStatusMonitorSocketHandler;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
...@@ -16,14 +16,18 @@ public class WebSocketConfig implements WebSocketConfigurer { ...@@ -16,14 +16,18 @@ public class WebSocketConfig implements WebSocketConfigurer {
private final ExecutionSocketHandler executionSocketHandler; private final ExecutionSocketHandler executionSocketHandler;
public WebSocketConfig(ExecutionSocketHandler executionSocketHandler) { private final ExecutionStatusMonitorSocketHandler executionStatusMonitorSocketHandler;
public WebSocketConfig(ExecutionSocketHandler executionSocketHandler,ExecutionStatusMonitorSocketHandler executionStatusMonitorSocketHandler) {
this.executionSocketHandler = executionSocketHandler; this.executionSocketHandler = executionSocketHandler;
this.executionStatusMonitorSocketHandler = executionStatusMonitorSocketHandler;
} }
@Override @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry registry
.addHandler(executionSocketHandler, "ws") .addHandler(executionSocketHandler, "ws")
.addHandler(executionStatusMonitorSocketHandler, "statusMonitor")
.setAllowedOrigins("*"); .setAllowedOrigins("*");
} }
} }
\ No newline at end of file
...@@ -27,12 +27,13 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> { ...@@ -27,12 +27,13 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> {
* @param jobId 测试任务ID * @param jobId 测试任务ID
* @param caseId 用例ID * @param caseId 用例ID
* @param userId 用户ID * @param userId 用户ID
* @param uniqueKey 批次号
* @return 执行记录列表 * @return 执行记录列表
*/ */
@Select("<script>" + @Select("<script>" +
"SELECT\n" + "SELECT\n" +
"\tkeh.id,\n" + "\tkeh.id,\n" +
"\tkeh.union_key uniqueKey,\n" + "\tkeh.unique_key uniqueKey,\n" +
"\tkeh.case_id caseId,\n" + "\tkeh.case_id caseId,\n" +
"\tkeh.data_id dataId,\n" + "\tkeh.data_id dataId,\n" +
"\tkeh.job_id jobId,\n" + "\tkeh.job_id jobId,\n" +
...@@ -56,10 +57,13 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> { ...@@ -56,10 +57,13 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> {
"<if test=\"jobId!=null\">\n" + "<if test=\"jobId!=null\">\n" +
"and keh.job_id= #{jobId} \n" + "and keh.job_id= #{jobId} \n" +
" </if>" + " </if>" +
"<if test=\"uniqueKey!=null and uniqueKey!=''\">" +
"and keh.`unique_key` = #{uniqueKey}" +
"</if>" +
"</where>" + "</where>" +
"GROUP BY keh.union_key " + "GROUP BY keh.unique_key " +
"</script>") "</script>")
IPage<ExecutionHistoryVo> pageByCaseIdAndJobId(IPage<ExecutionHistoryVo> page, Long caseId, Long jobId,Long userId); IPage<ExecutionHistoryVo> pageByCaseIdAndJobId(IPage<ExecutionHistoryVo> page, Long caseId, Long jobId,Long userId,String uniqueKey);
/** /**
* 查出最近一条的执行历史 * 查出最近一条的执行历史
...@@ -71,7 +75,7 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> { ...@@ -71,7 +75,7 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> {
@Select("<script>" + @Select("<script>" +
"SELECT\n" + "SELECT\n" +
"\tkeh.id,\n" + "\tkeh.id,\n" +
"\tkeh.union_key uniqueKey,\n" + "\tkeh.unique_key uniqueKey,\n" +
"\tkeh.case_id caseId,\n" + "\tkeh.case_id caseId,\n" +
"\tkeh.data_id dataId,\n" + "\tkeh.data_id dataId,\n" +
"\tkeh.job_id jobId,\n" + "\tkeh.job_id jobId,\n" +
...@@ -89,7 +93,7 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> { ...@@ -89,7 +93,7 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> {
"\tkt_execution_history keh\n" + "\tkt_execution_history keh\n" +
"\tLEFT JOIN kt_test_case ktc ON ktc.id = keh.case_id\n" + "\tLEFT JOIN kt_test_case ktc ON ktc.id = keh.case_id\n" +
"\tLEFT JOIN kt_test_data ktd ON ktd.id = keh.data_id \n" + "\tLEFT JOIN kt_test_data ktd ON ktd.id = keh.data_id \n" +
"\t WHERE keh.union_key = ( SELECT union_key FROM kt_execution_history WHERE id IN ( SELECT max( id ) FROM kt_execution_history " + "\t WHERE keh.unique_key = ( SELECT unique_key FROM kt_execution_history WHERE id IN ( SELECT max( id ) FROM kt_execution_history " +
"<where>" + "<where>" +
"<if test=\"userId!=null\">\n" + "<if test=\"userId!=null\">\n" +
"and user_id= #{userId} \n" + "and user_id= #{userId} \n" +
...@@ -103,7 +107,7 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> { ...@@ -103,7 +107,7 @@ public interface ExecutionHistoryMapper extends BaseMapper<ExecutionHistory> {
"</where>" + "</where>" +
"GROUP BY case_id ) ) \n" + "GROUP BY case_id ) ) \n" +
"GROUP BY\n" + "GROUP BY\n" +
"\tkeh.union_key\n" + "\tkeh.unique_key\n" +
"</script>") "</script>")
ExecutionHistoryVo selectLastExecutionHistoryVo( Long caseId, Long jobId,Long userId); ExecutionHistoryVo selectLastExecutionHistoryVo( Long caseId, Long jobId,Long userId);
......
...@@ -26,8 +26,8 @@ public interface TestJobMapper extends BaseMapper<TestJob> { ...@@ -26,8 +26,8 @@ public interface TestJobMapper extends BaseMapper<TestJob> {
"\t`status` \n" + "\t`status` \n" +
"FROM\n" + "FROM\n" +
"\t`kt_test_job` ktj\n" + "\t`kt_test_job` ktj\n" +
"\tLEFT JOIN ( SELECT job_id, union_key FROM kt_execution_history WHERE id IN ( SELECT max( id ) FROM kt_execution_history WHERE job_id != - 1 GROUP BY job_id ) ) keh ON ktj.id = keh.job_id\n" + "\tLEFT JOIN ( SELECT job_id, unique_key FROM kt_execution_history WHERE id IN ( SELECT max( id ) FROM kt_execution_history WHERE job_id != - 1 GROUP BY job_id ) ) keh ON ktj.id = keh.job_id\n" +
"\tLEFT JOIN ( SELECT union_key, IF ( MIN( `status` )= 0, 0, MAX( `status` )) `status` FROM kt_execution_history GROUP BY union_key ) us ON us.union_key = keh.union_key" + "\tLEFT JOIN ( SELECT unique_key, IF ( MIN( `status` )= 0, 0, MAX( `status` )) `status` FROM kt_execution_history GROUP BY unique_key ) us ON us.unique_key = keh.unique_key" +
"<where>" + "<where>" +
"<if test=\"name!=null and name!=''\">" + "<if test=\"name!=null and name!=''\">" +
"and ktj.`name` like concat('%',#{name},'%')" + "and ktj.`name` like concat('%',#{name},'%')" +
......
...@@ -22,9 +22,10 @@ public interface IExecutionHistoryService extends IService<ExecutionHistory> { ...@@ -22,9 +22,10 @@ public interface IExecutionHistoryService extends IService<ExecutionHistory> {
* @param pageSize 分页条数 * @param pageSize 分页条数
* @param jobId 测试任务ID * @param jobId 测试任务ID
* @param caseId 用例ID * @param caseId 用例ID
* @uniqueKey caseId 批次号
* @return 执行记录列表 * @return 执行记录列表
*/ */
IPage<ExecutionHistoryVo> pageExecutionHistoryVoByCaseIdAndJobId(Long caseId, Long jobId, int pageSize, int pageNum); IPage<ExecutionHistoryVo> pageExecutionHistoryVoByCaseIdAndJobId(Long caseId, Long jobId,String uniqueKey, int pageSize, int pageNum);
/** /**
* 根据CaseId和JobId 查询对应的最后一次执行记录 * 根据CaseId和JobId 查询对应的最后一次执行记录
......
...@@ -33,10 +33,10 @@ import static java.util.Comparator.comparingLong; ...@@ -33,10 +33,10 @@ import static java.util.Comparator.comparingLong;
public class ExecutionHistoryServiceImpl extends ServiceImpl<ExecutionHistoryMapper, ExecutionHistory> implements IExecutionHistoryService { public class ExecutionHistoryServiceImpl extends ServiceImpl<ExecutionHistoryMapper, ExecutionHistory> implements IExecutionHistoryService {
@Override @Override
public IPage<ExecutionHistoryVo> pageExecutionHistoryVoByCaseIdAndJobId(Long caseId, Long jobId, int pageNum, int pageSize ) { public IPage<ExecutionHistoryVo> pageExecutionHistoryVoByCaseIdAndJobId(Long caseId, Long jobId,String uniqueKey, int pageNum, int pageSize ) {
// todo 黄夏豪 等待接入用户ID // todo 黄夏豪 等待接入用户ID
Page<ExecutionHistoryVo> page = new Page<>(pageNum, pageSize); Page<ExecutionHistoryVo> page = new Page<>(pageNum, pageSize);
return baseMapper.pageByCaseIdAndJobId(page,caseId,jobId,1L); return baseMapper.pageByCaseIdAndJobId(page,caseId,jobId,1L,uniqueKey);
} }
@Override @Override
......
package org.matrix.database.vo;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.matrix.database.entity.BaseEntity;
import org.matrix.database.entity.ExecutionRecord;
import org.matrix.socket.enums.TestExecuteType;
/**
* @author mry
*/
@Data
public class ExecutionRecordVo extends ExecutionRecord {
private String jobName;
private String caseName;
private String dataName;
}
package org.matrix.socket; package org.matrix.socket;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.beanutils.BeanUtils;
import org.matrix.actuators.datasource.IDataSourceService;
import org.matrix.actuators.sql.SqlExpActuator;
import org.matrix.actuators.usecase.CaseActuator; import org.matrix.actuators.usecase.CaseActuator;
import org.matrix.database.entity.TestCase;
import org.matrix.database.entity.TestCaseListDataBto;
import org.matrix.database.entity.TestData;
import org.matrix.database.entity.TestJob;
import org.matrix.database.service.ITestCaseService;
import org.matrix.database.service.ITestDataService; import org.matrix.database.service.ITestDataService;
import org.matrix.database.service.ITestJobService;
import org.matrix.exception.GlobalException;
import org.matrix.socket.enums.SocketType; import org.matrix.socket.enums.SocketType;
import org.matrix.socket.pool.MonitorSocketPool; import org.matrix.socket.pool.MonitorSocketPool;
import org.matrix.socket.vo.CaseExecuteVo; import org.matrix.socket.vo.CaseExecuteVo;
import org.matrix.socket.vo.ExecuteMonitorVo; import org.matrix.socket.vo.ExecuteMonitorVo;
import org.matrix.socket.vo.SocketVo; import org.matrix.socket.vo.SocketVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler; import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/** /**
* webSocket处理 调用和执行的日志发送 * webSocket处理 调用和执行的日志发送
* *
...@@ -27,10 +46,20 @@ public class ExecutionSocketHandler extends TextWebSocketHandler { ...@@ -27,10 +46,20 @@ public class ExecutionSocketHandler extends TextWebSocketHandler {
final CaseActuator caseActuator; final CaseActuator caseActuator;
final ITestDataService testDataService; final ITestDataService testDataService;
final ITestJobService testJobService;
final ITestCaseService testCaseService;
final SqlExpActuator sqlExpActuator;
final JdbcTemplate jdbcTemplate;
final IDataSourceService dataSourceService;
public ExecutionSocketHandler(CaseActuator caseActuator, ITestDataService testDataService) { public ExecutionSocketHandler(CaseActuator caseActuator, ITestDataService testDataService, ITestJobService testJobService, ITestCaseService testCaseService, SqlExpActuator sqlExpActuator, JdbcTemplate jdbcTemplate, IDataSourceService dataSourceService) {
this.caseActuator = caseActuator; this.caseActuator = caseActuator;
this.testDataService = testDataService; this.testDataService = testDataService;
this.testJobService = testJobService;
this.testCaseService = testCaseService;
this.sqlExpActuator = sqlExpActuator;
this.jdbcTemplate = jdbcTemplate;
this.dataSourceService = dataSourceService;
} }
@Override @Override
...@@ -44,23 +73,47 @@ public class ExecutionSocketHandler extends TextWebSocketHandler { ...@@ -44,23 +73,47 @@ public class ExecutionSocketHandler extends TextWebSocketHandler {
if (SocketType.TEST_CASE_EXECUTE.equals(socketVo.getSocketType())) { if (SocketType.TEST_CASE_EXECUTE.equals(socketVo.getSocketType())) {
CaseExecuteVo caseExecuteVo = JSON.parseObject(payload, CaseExecuteVo.class); CaseExecuteVo caseExecuteVo = JSON.parseObject(payload, CaseExecuteVo.class);
caseActuator.runTestCase(session, caseExecuteVo); caseActuator.runTestCase(session, caseExecuteVo);
} else if (SocketType.TEST_JOB_EXECUTE.equals(socketVo.getSocketType())) {
CaseExecuteVo caseExecuteVo = JSON.parseObject(payload, CaseExecuteVo.class);
TestJob byId = testJobService.getById(caseExecuteVo.getJobId());
String sqlStatement = byId.getSqlStatement();
dataSourceService.switchMainDataSource();
List<Map<String, Object>> list = jdbcTemplate.queryForList(sqlStatement);
List<TestCase> testCaseList = new ArrayList<>();
for (Map<String, Object> objectMap : list) {
TestCase testCase = BeanUtil.mapToBean(objectMap,TestCase.class,false);
testCaseList.add(testCase);
}
for (TestCase testCase : testCaseList) {
List<TestData> testDataList = testDataService.list(Wrappers.lambdaQuery(TestData.class).eq(TestData::getTestCaseId, testCase.getId()));
TestCaseListDataBto testCaseListDataBto = new TestCaseListDataBto();
testCaseListDataBto.setTestCase(testCase);
testCaseListDataBto.setTestDataList(testDataList);
caseExecuteVo.getTestCaseListDataBtoList().add(testCaseListDataBto);
}
if (testCaseList.size()>0){
caseExecuteVo.setProjectId(testCaseList.get(0).getProjectId());
}
session.sendMessage(new TextMessage(JSONObject.toJSONString(caseExecuteVo)));
caseActuator.runTestCase(session, caseExecuteVo);
} else if (SocketType.TEST_CASE_MONITOR.equals(socketVo.getSocketType())) { } else if (SocketType.TEST_CASE_MONITOR.equals(socketVo.getSocketType())) {
ExecuteMonitorVo caseExecuteVo = JSON.parseObject(payload, ExecuteMonitorVo.class); ExecuteMonitorVo caseExecuteVo = JSON.parseObject(payload, ExecuteMonitorVo.class);
EXECUTE_MONITOR_SOCKET_POOL.add(caseExecuteVo.getUniqueKey(), session); EXECUTE_MONITOR_SOCKET_POOL.add(caseExecuteVo.getUniqueKey(), session);
} else { } else {
session.sendMessage(new TextMessage("入参不符合规定")); throw new GlobalException("入参不符合规定");
} }
} }
} catch (JSONException e) { } catch (Exception e) {
session.sendMessage(new TextMessage("入参不符合规定")); e.printStackTrace();
session.sendMessage(new TextMessage(e.getMessage()));
} }
} }
@Override @Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
EXECUTE_MONITOR_SOCKET_POOL.remove(session); EXECUTE_MONITOR_SOCKET_POOL.remove(session);
} }
} }
package org.matrix.socket;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.matrix.database.entity.ExecutionHistory;
import org.matrix.database.service.IExecutionHistoryService;
import org.matrix.database.vo.ExecutionHistoryVo;
import org.matrix.enums.ExecutionHistoryStatus;
import org.matrix.socket.enums.ExecuteStatusSendMessageType;
import org.matrix.socket.pool.MonitorSocketPool;
import org.matrix.socket.vo.ExecutionStatusMonitorVo;
import org.matrix.socket.vo.ExecutionStatusSendMessageVo;
import org.matrix.socket.vo.TestExecuteLog;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.List;
/**
* webSocket处理
* 订阅用例调试和测试任务执行的
*
* @author huangxiahao
*/
@Component
public class ExecutionStatusMonitorSocketHandler extends TextWebSocketHandler {
public static final MonitorSocketPool EXECUTE_MONITOR_SOCKET_POOL = new MonitorSocketPool();
private final IExecutionHistoryService executionHistoryService;
public ExecutionStatusMonitorSocketHandler(IExecutionHistoryService executionHistoryService) {
this.executionHistoryService = executionHistoryService;
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
String payload = message.getPayload();
ExecutionStatusMonitorVo executionStatusMonitorVo = JSON.parseObject(payload, ExecutionStatusMonitorVo.class);
if (executionStatusMonitorVo != null && executionStatusMonitorVo.getExecuteStatusMonitorType() != null) {
switch (executionStatusMonitorVo.getExecuteStatusMonitorType()) {
case DETAIL:
if (!StringUtils.isEmpty(executionStatusMonitorVo.getUniqueKey())&&executionStatusMonitorVo.getCaseId()!=null&&executionStatusMonitorVo.getDataId()!=null){
EXECUTE_MONITOR_SOCKET_POOL.add(String.format("%s.%s.%s.%s.%s",
executionStatusMonitorVo.getUserId(),
executionStatusMonitorVo.getJobId(),
executionStatusMonitorVo.getCaseId(),
executionStatusMonitorVo.getDataId(),
executionStatusMonitorVo.getUniqueKey()
), session);
}
sendDetailCurrentStatus(
executionStatusMonitorVo.getUserId(),
executionStatusMonitorVo.getJobId(),
executionStatusMonitorVo.getCaseId(),
executionStatusMonitorVo.getDataId(),
executionStatusMonitorVo.getUniqueKey(),
null
);
break;
default:
if (!StringUtils.isEmpty(executionStatusMonitorVo.getUniqueKey())){
EXECUTE_MONITOR_SOCKET_POOL.add(executionStatusMonitorVo.getUniqueKey(), session);
sendOverviewCurrentStatus(executionStatusMonitorVo.getUniqueKey());
}
}
} else {
session.sendMessage(new TextMessage("入参不符合规定"));
}
}
public void sendOverviewCurrentStatus(String uniqueKey) throws IOException {
//获取该数据当前执行状态
IPage<ExecutionHistoryVo> page = executionHistoryService.pageExecutionHistoryVoByCaseIdAndJobId(null, null, uniqueKey, 1, 10);
if (page.getRecords() != null && page.getRecords().size() > 0) {
ExecutionHistoryStatus status = page.getRecords().get(0).getStatus();
ExecutionStatusSendMessageVo sendMessageVo = new ExecutionStatusSendMessageVo(
uniqueKey,
null,
null,
null,
status,
ExecuteStatusSendMessageType.OVERVIEW
);
List<WebSocketSession> webSocketSessions = EXECUTE_MONITOR_SOCKET_POOL.get(uniqueKey);
if (webSocketSessions!=null){
for (WebSocketSession webSocketSession : webSocketSessions) {
webSocketSession.sendMessage(new TextMessage(JSONObject.toJSONString(sendMessageVo)));
}
}
}
}
public void sendDetailCurrentStatus(Long userId,Long jobId,Long caseId,Long dataId,String uniqueKey,ExecutionHistoryStatus status) throws IOException {
//获取该数据当前执行状态
String key = String.format("%s.%s.%s.%s.%s",
userId,
jobId,
caseId,
dataId,
uniqueKey
);
if (status==null){
LambdaQueryWrapper<ExecutionHistory> eq = Wrappers.lambdaQuery(ExecutionHistory.class)
.eq(ExecutionHistory::getUserId, userId)
.eq(ExecutionHistory::getJobId, jobId)
.eq(ExecutionHistory::getCaseId, caseId)
.eq(ExecutionHistory::getDataId, dataId)
.eq(ExecutionHistory::getUniqueKey, uniqueKey);
ExecutionHistory one = executionHistoryService.getOne(eq);
if (one!=null){
status = one.getStatus();
}
}
List<WebSocketSession> webSocketSessions = EXECUTE_MONITOR_SOCKET_POOL.get(key);
ExecutionStatusSendMessageVo sendMessageVo = new ExecutionStatusSendMessageVo(
uniqueKey,
jobId,
caseId,
dataId,
status,
ExecuteStatusSendMessageType.Data
);
if (webSocketSessions!=null){
for (WebSocketSession webSocketSession : webSocketSessions) {
webSocketSession.sendMessage(new TextMessage(JSONObject.toJSONString(sendMessageVo)));
}
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
EXECUTE_MONITOR_SOCKET_POOL.remove(session);
}
}
package org.matrix.socket;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
/**
* webSocket处理
* 订阅用例调试和测试任务执行的
*
* @author huangxiahao
*/
@Component
public class ExecutionStatusMonitorSocketPool extends TextWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
}
}
package org.matrix.socket.enums;
/**
* @author huangxiahao
*/
public enum ExecuteStatusMonitorType {
/**
* 订阅批次状态
*/
OVERVIEW,
/**
* 订阅具体的数据状态
*/
DETAIL
;
}
package org.matrix.socket.enums;
/**
* @author huangxiahao
*/
public enum ExecuteStatusSendMessageType {
/**
* 改变了批次状态
*/
OVERVIEW,
/**
* 改变了实例状态
*/
Data
;
}
...@@ -10,6 +10,7 @@ public enum SocketType { ...@@ -10,6 +10,7 @@ public enum SocketType {
* 测试用例类型 * 测试用例类型
*/ */
TEST_CASE_EXECUTE, TEST_CASE_EXECUTE,
TEST_JOB_EXECUTE,
TEST_CASE_MONITOR; TEST_CASE_MONITOR;
} }
package org.matrix.socket.pool; package org.matrix.socket.pool;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* 订阅执行日志的池子 * 订阅的池子
* *
* @author huangxiahao * @author huangxiahao
*/ */
...@@ -25,11 +27,16 @@ public class MonitorSocketPool { ...@@ -25,11 +27,16 @@ public class MonitorSocketPool {
*/ */
private ConcurrentHashMap<String, List<String>> socketKeyMap = new ConcurrentHashMap<>(); private ConcurrentHashMap<String, List<String>> socketKeyMap = new ConcurrentHashMap<>();
public void add(String key, WebSocketSession clientSocket) { public void add(String key, WebSocketSession clientSocket) throws IOException {
if (clientSocket != null & key != null) { if (clientSocket != null & key != null) {
List<WebSocketSession> webSocketSessions = socketMap.get(key); List<WebSocketSession> webSocketSessions = socketMap.get(key);
if (webSocketSessions != null) { if (webSocketSessions != null) {
webSocketSessions.add(clientSocket); List<String> list = socketKeyMap.get(clientSocket.getId());
if (list!=null&&list.contains(key)){
clientSocket.sendMessage(new TextMessage("请勿重复订阅"));
}else {
webSocketSessions.add(clientSocket);
}
} else { } else {
webSocketSessions = new ArrayList<>(); webSocketSessions = new ArrayList<>();
webSocketSessions.add(clientSocket); webSocketSessions.add(clientSocket);
...@@ -57,7 +64,11 @@ public class MonitorSocketPool { ...@@ -57,7 +64,11 @@ public class MonitorSocketPool {
List<String> list = socketKeyMap.get(socketId); List<String> list = socketKeyMap.get(socketId);
if (list != null) { if (list != null) {
for (String s : list) { for (String s : list) {
socketMap.get(s);
socketMap.get(s).remove(clientSocket); socketMap.get(s).remove(clientSocket);
if (socketMap.get(s).size()==0){
socketMap.remove(s);
}
} }
} }
socketKeyMap.remove(socketId); socketKeyMap.remove(socketId);
......
package org.matrix.socket.vo; package org.matrix.socket.vo;
import lombok.Data; import lombok.Data;
import org.matrix.socket.enums.ExecuteStatusMonitorType;
import org.matrix.socket.enums.TestExecuteType;
import java.util.List;
/** /**
* 前端需要监听某一个测试任务或者测试用例调试时需要传入的值 * 前端需要监听某一个测试任务或者测试用例调试时需要传入的值
...@@ -9,6 +13,16 @@ import lombok.Data; ...@@ -9,6 +13,16 @@ import lombok.Data;
@Data @Data
public class ExecutionStatusMonitorVo { public class ExecutionStatusMonitorVo {
private String uniqueKey;
private Long userId;
private Long jobId = -1L;
private Long caseId ;
private Long dataId;
private ExecuteStatusMonitorType executeStatusMonitorType;
} }
package org.matrix.socket.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.matrix.enums.ExecutionHistoryStatus;
import org.matrix.socket.enums.ExecuteStatusSendMessageType;
/**
* 当订阅的执行任务或者用例调试的状态发生变化的时候 向外界发送状态所用到的VO
* @author huangxiahao
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExecutionStatusSendMessageVo {
private String uniqueKey;
private Long jobId;
private Long caseId;
private Long dataId;
private ExecutionHistoryStatus status;
private ExecuteStatusSendMessageType type;
}
...@@ -90,27 +90,27 @@ public class TestPigeon extends AbstractTestNGSpringContextTests { ...@@ -90,27 +90,27 @@ public class TestPigeon extends AbstractTestNGSpringContextTests {
@Test(dataProvider = "testData") @Test(dataProvider = "testData")
public void test(Map<String, String> data) { public void test(Map<String, String> data) {
log.info("这是testData"); // log.info("这是testData");
String id = data.get("id"); // String id = data.get("id");
long caseId = Long.parseLong(id); // long caseId = Long.parseLong(id);
TestCase testCase = java.util.Optional.of(caseService.getById(caseId)) // TestCase testCase = java.util.Optional.of(caseService.getById(caseId))
.orElseThrow(() -> new GlobalException(String.format("没有找到id = %d 的TestCase", caseId))); // .orElseThrow(() -> new GlobalException(String.format("没有找到id = %d 的TestCase", caseId)));
List<TestData> testDataList = java.util.Optional.of(dataService.list(Wrappers.lambdaQuery(TestData.class) // List<TestData> testDataList = java.util.Optional.of(dataService.list(Wrappers.lambdaQuery(TestData.class)
.eq(TestData::getTestCaseId, caseId))) // .eq(TestData::getTestCaseId, caseId)))
.orElseThrow(() -> new GlobalException(String.format("没有找到testCaseId = %d 的TestData", caseId))); // .orElseThrow(() -> new GlobalException(String.format("没有找到testCaseId = %d 的TestData", caseId)));
CaseExecuteVo caseExecuteVo = new CaseExecuteVo(); // CaseExecuteVo caseExecuteVo = new CaseExecuteVo();
caseExecuteVo.setProjectId(testCase.getProjectId()); // caseExecuteVo.setProjectId(testCase.getProjectId());
caseExecuteVo.setEnvId(envId); // caseExecuteVo.setEnvId(envId);
caseExecuteVo.setUserId(1L); // caseExecuteVo.setUserId(1L);
caseExecuteVo.getTestCaseListDataBtoList().add( // caseExecuteVo.getTestCaseListDataBtoList().add(
new TestCaseListDataBto( // new TestCaseListDataBto(
testCase, // testCase,
testDataList // testDataList
) // )
); // );
List<TestCaseExecuteResult> testCaseExecuteResults = caseActuator.runTestCase(null, caseExecuteVo); // List<TestCaseExecuteResult> testCaseExecuteResults = caseActuator.runTestCase(null, caseExecuteVo);
resultMap.put(caseId, testCaseExecuteResults); // resultMap.put(caseId, testCaseExecuteResults);
userResultMap.put(1L, resultMap); // userResultMap.put(1L, resultMap);
} }
......
package org.matrix.actuators.http; package org.matrix.actuators.http;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.matrix.actuators.httpclient.HttpClientActuator; import org.matrix.actuators.httpclient.HttpClientActuator;
import org.matrix.actuators.httpclient.HttpRequestDetail; import org.matrix.actuators.httpclient.HttpRequestDetail;
import org.matrix.actuators.httpclient.HttpResponseDetail; import org.matrix.actuators.httpclient.HttpResponseDetail;
import org.matrix.config.HttpRequestConfig; import org.matrix.config.HttpRequestConfig;
import org.matrix.database.entity.ExecutionRecord;
import org.matrix.database.service.IExecutionRecordService;
import org.matrix.exception.GlobalException;
import org.matrix.socket.enums.TestExecuteType;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static java.util.stream.Collectors.groupingBy;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest @SpringBootTest
...@@ -18,6 +32,9 @@ class HttpClientActuatorTest { ...@@ -18,6 +32,9 @@ class HttpClientActuatorTest {
@Autowired @Autowired
HttpClientActuator httpClientActuator; HttpClientActuator httpClientActuator;
@Autowired
IExecutionRecordService executionRecordService;
@Test @Test
void test(){ void test(){
...@@ -38,5 +55,65 @@ class HttpClientActuatorTest { ...@@ -38,5 +55,65 @@ class HttpClientActuatorTest {
HttpResponseDetail httpResponseDetail = httpClientActuator.sendHttpRequest(httpRequestDetail,1l,1l); HttpResponseDetail httpResponseDetail = httpClientActuator.sendHttpRequest(httpRequestDetail,1l,1l);
System.out.println(httpResponseDetail); System.out.println(httpResponseDetail);
} }
@Test
void test2(){
List<ExecutionRecord> results = getExecutionRecords(1L, null, null, "e9e0a9cd-df63-4fea-9992-68d31c8b2160", null);
Map<Long, Map<Long, Map<Long, List<ExecutionRecord>>>> map = results.stream().collect(
groupingBy(ExecutionRecord::getTestJobId,
groupingBy(ExecutionRecord::getTestCaseId,
groupingBy(ExecutionRecord::getTestDataId))));
System.out.println("1");
}
List<ExecutionRecord> getExecutionRecords(Long userId, Long testDataId, Long testCaseId, String uniqueKey, TestExecuteType type) {
List<ExecutionRecord> results = Optional.of(executionRecordService.list(
Wrappers.lambdaQuery(ExecutionRecord.class)
.eq(userId != null, ExecutionRecord::getUserId, userId)
.eq(testDataId != null, ExecutionRecord::getTestDataId, testDataId)
.eq(testCaseId != null, ExecutionRecord::getTestCaseId, testCaseId)
.eq(StringUtils.hasLength(uniqueKey), ExecutionRecord::getUniqueKey, uniqueKey)
.eq(type != null, ExecutionRecord::getType, type)
)).orElseThrow(() -> new GlobalException("xxx"));
return results;
}
void putValueToNext(ExecutionRecord record, JSONObject resultJson, JSONArray jsonArray, int num){
if (num==4){
jsonArray.add(record.getLog());
}else {
if (num==1){
JSONObject jsonObject = resultJson.getJSONObject(record.getTestJobId() + "");
if (jsonObject!=null){
putValueToNext(record,jsonObject,jsonArray,2);
}else {
JSONObject newJsonObject = new JSONObject();
resultJson.put(record.getTestJobId() + "",newJsonObject);
putValueToNext(record,newJsonObject,jsonArray,2);
}
}
if (num==2){
JSONObject jsonObject = resultJson.getJSONObject(record.getTestCaseId() + "");
if (jsonObject!=null){
putValueToNext(record,jsonObject,jsonArray,3);
}else {
JSONObject newJsonObject = new JSONObject();
resultJson.put(record.getTestCaseId() + "",newJsonObject);
putValueToNext(record,newJsonObject,jsonArray,3);
}
}
if (num==3){
JSONObject jsonObject = resultJson.getJSONObject(record.getTestDataId() + "");
if (jsonObject!=null){
putValueToNext(record,jsonObject,jsonArray,4);
}else {
JSONArray newJsonArray = new JSONArray();
resultJson.put(record.getTestDataId() + "",newJsonArray);
putValueToNext(record,null,jsonArray,4);
}
}
}
}
} }
...@@ -51,7 +51,7 @@ public class ExecutionHistoryController { ...@@ -51,7 +51,7 @@ public class ExecutionHistoryController {
@ApiImplicitParam(name="jobId",value="测试任务ID",paramType="query"), @ApiImplicitParam(name="jobId",value="测试任务ID",paramType="query"),
@ApiImplicitParam(name="caseId",value="测试用例ID",paramType="query") @ApiImplicitParam(name="caseId",value="测试用例ID",paramType="query")
}) })
public ResponseEntity<CommonResultObj<IPage<ExecutionHistoryVo>>> findExecutionHistory( public ResponseEntity<CommonResultObj<IPage<ExecutionHistoryVo>>> executionHistoryDetail(
@RequestParam(defaultValue = "10") int pageSize, @RequestParam(defaultValue = "10") int pageSize,
@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "-1") Long jobId, @RequestParam(defaultValue = "-1") Long jobId,
...@@ -87,15 +87,17 @@ public class ExecutionHistoryController { ...@@ -87,15 +87,17 @@ public class ExecutionHistoryController {
@ApiImplicitParam(name="pageSize",value="页码",required=true,paramType="query"), @ApiImplicitParam(name="pageSize",value="页码",required=true,paramType="query"),
@ApiImplicitParam(name="pageNum",value="当前页显示调试",required=true,paramType="query"), @ApiImplicitParam(name="pageNum",value="当前页显示调试",required=true,paramType="query"),
@ApiImplicitParam(name="jobId",value="测试任务ID",paramType="query"), @ApiImplicitParam(name="jobId",value="测试任务ID",paramType="query"),
@ApiImplicitParam(name="caseId",value="测试用例ID",paramType="query") @ApiImplicitParam(name="caseId",value="测试用例ID",paramType="query"),
@ApiImplicitParam(name="uniqueKey",value="执行历史批次号",paramType="query"),
}) })
public ResponseEntity<CommonResultObj<IPage<ExecutionHistoryVo>>> findExecutionHistory( public ResponseEntity<CommonResultObj<IPage<ExecutionHistoryVo>>> findExecutionHistory(
@RequestParam(defaultValue = "10") int pageSize, @RequestParam(defaultValue = "10") int pageSize,
@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "-1") Long jobId, @RequestParam(defaultValue = "-1") Long jobId,
Long caseId Long caseId,
){ String uniqueKey
IPage<ExecutionHistoryVo> page = executionHistoryService.pageExecutionHistoryVoByCaseIdAndJobId(caseId, jobId, pageNum, pageSize); ){
IPage<ExecutionHistoryVo> page = executionHistoryService.pageExecutionHistoryVoByCaseIdAndJobId(caseId, jobId,uniqueKey, pageNum, pageSize);
return page.getRecords().size() != 0 return page.getRecords().size() != 0
? CommonResult.success(page, "查询成功") ? CommonResult.success(page, "查询成功")
: CommonResult.failed(page, "查询失败或无数据"); : CommonResult.failed(page, "查询失败或无数据");
...@@ -117,5 +119,4 @@ public class ExecutionHistoryController { ...@@ -117,5 +119,4 @@ public class ExecutionHistoryController {
: CommonResult.failed(null, "查询失败或无数据"); : CommonResult.failed(null, "查询失败或无数据");
} }
} }
package org.matrix.autotest.controller; package org.matrix.autotest.controller;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.matrix.autotest.utils.PageTools; import org.matrix.autotest.utils.PageTools;
import org.matrix.database.entity.ExecutionRecord; import org.matrix.database.entity.ExecutionRecord;
import org.matrix.database.entity.TestJob;
import org.matrix.database.service.IExecutionRecordService; import org.matrix.database.service.IExecutionRecordService;
import org.matrix.database.service.ITestCaseService;
import org.matrix.database.service.ITestDataService;
import org.matrix.database.service.ITestJobService;
import org.matrix.database.vo.CommonResult; import org.matrix.database.vo.CommonResult;
import org.matrix.database.vo.CommonResultObj; import org.matrix.database.vo.CommonResultObj;
import org.matrix.database.vo.ExecutionRecordVo;
import org.matrix.enums.ExecutionRecType; import org.matrix.enums.ExecutionRecType;
import org.matrix.exception.GlobalException; import org.matrix.exception.GlobalException;
import org.matrix.socket.enums.TestExecuteType; import org.matrix.socket.enums.TestExecuteType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.*;
import java.util.Optional; import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.*;
/** /**
* @author mry * @author mry
...@@ -30,8 +43,20 @@ public class ExecutionRecordController { ...@@ -30,8 +43,20 @@ public class ExecutionRecordController {
private final IExecutionRecordService executionRecordService; private final IExecutionRecordService executionRecordService;
public ExecutionRecordController(IExecutionRecordService executionRecordService) { final
ITestJobService testJobService;
final
ITestCaseService testCaseService;
final
ITestDataService testDataService;
public ExecutionRecordController(IExecutionRecordService executionRecordService, ITestJobService testJobService, ITestCaseService testCaseService, ITestDataService testDataService) {
this.executionRecordService = executionRecordService; this.executionRecordService = executionRecordService;
this.testJobService = testJobService;
this.testCaseService = testCaseService;
this.testDataService = testDataService;
} }
/** /**
...@@ -42,7 +67,7 @@ public class ExecutionRecordController { ...@@ -42,7 +67,7 @@ public class ExecutionRecordController {
* @param userId 查询条件:用户ID * @param userId 查询条件:用户ID
* @param testDataId 查询条件:测试数据ID * @param testDataId 查询条件:测试数据ID
* @param testCaseId 查询条件:测试用例ID * @param testCaseId 查询条件:测试用例ID
* @param uniqueKey 查询条件:唯一批次号 * @param uniqueKey 查询条件:唯一批次号
* @param status 查询条件:运行状态 * @param status 查询条件:运行状态
* @param type 查询条件:执行类型 * @param type 查询条件:执行类型
* @return 分页查询的结果, 执行记录 * @return 分页查询的结果, 执行记录
...@@ -78,20 +103,64 @@ public class ExecutionRecordController { ...@@ -78,20 +103,64 @@ public class ExecutionRecordController {
* @param userId 查询条件:用户ID * @param userId 查询条件:用户ID
* @param testDataId 查询条件:测试数据ID * @param testDataId 查询条件:测试数据ID
* @param testCaseId 查询条件:测试用例ID * @param testCaseId 查询条件:测试用例ID
* @param uniqueKey 查询条件:唯一批次号 * @param uniqueKey 查询条件:唯一批次号
* @param status 查询条件:运行状态
* @param type 查询条件:执行类型 * @param type 查询条件:执行类型
* @return 分页查询的结果, 执行记录 * @return 分页查询的结果, 执行记录
*/ */
@ApiOperation("分页查询执行记录") @ApiOperation("列表查询执行记录")
@GetMapping("/list") @GetMapping("/list")
public ResponseEntity<CommonResultObj<List<ExecutionRecord>>> findListExecutionRecord( public ResponseEntity<CommonResultObj<List<ExecutionRecord>>> findListExecutionRecord(
Long userId, Long userId,
Long testDataId, Long testDataId,
Long testCaseId, Long testCaseId,
String uniqueKey, String uniqueKey,
ExecutionRecType status,
TestExecuteType type) { TestExecuteType type) {
List<ExecutionRecord> results = getExecutionRecords(userId, testDataId, testCaseId, uniqueKey, type);
Map<Long, Map<Long, Map<Long, List<String>>>> resultMap = new HashMap<>();
return results.size() != 0
? CommonResult.success(results, "查询成功")
: CommonResult.failed(results, "查询失败或无数据");
}
/**
* 分页查询执行记录
*
* @param userId 查询条件:用户ID
* @param testDataId 查询条件:测试数据ID
* @param testCaseId 查询条件:测试用例ID
* @param uniqueKey 查询条件:唯一批次号
* @param type 查询条件:执行类型
* @return 分页查询的结果, 执行记录
*/
@ApiOperation("树状查询执行记录")
@GetMapping("/tree")
public ResponseEntity<CommonResultObj<Map<Long, Map<Long, Map<Long, List<ExecutionRecordVo>>>>>> tree(
Long userId,
Long testDataId,
Long testCaseId,
String uniqueKey,
TestExecuteType type) {
List<ExecutionRecord> results = getExecutionRecords(userId, testDataId, testCaseId, uniqueKey, type);
List<ExecutionRecordVo> list = new ArrayList<>();
for (ExecutionRecord result : results) {
ExecutionRecordVo recordVo = new ExecutionRecordVo();
BeanUtils.copyProperties(result,recordVo);
recordVo.setJobName(testJobService.getById(result.getTestJobId()).getName());
recordVo.setCaseName(testCaseService.getById(result.getTestCaseId()).getName());
if (recordVo.getTestDataId()!=-1L){
recordVo.setDataName(testDataService.getById(result.getTestDataId()).getName());
}
list.add(recordVo);
}
Map<Long, Map<Long, Map<Long, List<ExecutionRecordVo>>>> map = list.stream().collect(
groupingBy(ExecutionRecord::getTestJobId,
groupingBy(ExecutionRecord::getTestCaseId,
groupingBy(ExecutionRecord::getTestDataId))));
return CommonResult.success(map, "查询成功");
}
private List<ExecutionRecord> getExecutionRecords(Long userId, Long testDataId, Long testCaseId, String uniqueKey, TestExecuteType type) {
List<ExecutionRecord> results = Optional.of(executionRecordService.list( List<ExecutionRecord> results = Optional.of(executionRecordService.list(
Wrappers.lambdaQuery(ExecutionRecord.class) Wrappers.lambdaQuery(ExecutionRecord.class)
.eq(userId != null, ExecutionRecord::getUserId, userId) .eq(userId != null, ExecutionRecord::getUserId, userId)
...@@ -99,12 +168,11 @@ public class ExecutionRecordController { ...@@ -99,12 +168,11 @@ public class ExecutionRecordController {
.eq(testCaseId != null, ExecutionRecord::getTestCaseId, testCaseId) .eq(testCaseId != null, ExecutionRecord::getTestCaseId, testCaseId)
.eq(StringUtils.hasLength(uniqueKey), ExecutionRecord::getUniqueKey, uniqueKey) .eq(StringUtils.hasLength(uniqueKey), ExecutionRecord::getUniqueKey, uniqueKey)
.eq(type != null, ExecutionRecord::getType, type) .eq(type != null, ExecutionRecord::getType, type)
)).orElseThrow(()->new GlobalException("xxx")); )).orElseThrow(() -> new GlobalException("xxx"));
return results.size() != 0 return results;
? CommonResult.success(results, "查询成功")
: CommonResult.failed(results, "查询失败或无数据");
} }
/** /**
* 添加执行记录 * 添加执行记录
* *
......
package org.matrix; package org.matrix;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.matrix.database.entity.ExecutionRecord;
import org.matrix.database.service.IExecutionRecordService;
import org.matrix.exception.GlobalException;
import org.matrix.socket.enums.TestExecuteType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Optional;
/** /**
* Unit test for simple App. * Unit test for simple App.
*/ */
@RunWith(SpringRunner.class)
@SpringBootTest @SpringBootTest
public class AppTest { public class AppTest {
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论