Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
kt-keystone
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Matrix
kt-keystone
Commits
f38e0b2e
提交
f38e0b2e
authored
3月 09, 2022
作者:
Matrix
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(行为执行器): 增加了行为执行器的运行与行为变量解析
上级
acd1e56e
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
509 行增加
和
8 行删除
+509
-8
HttpResponseDetail.java
...a/org/matrix/actuators/httpclient/HttpResponseDetail.java
+2
-0
MoveActuator.java
...src/main/java/org/matrix/actuators/move/MoveActuator.java
+273
-0
MoveRegularObject.java
...ain/java/org/matrix/actuators/move/MoveRegularObject.java
+28
-0
MoveStrategy.java
...src/main/java/org/matrix/actuators/move/MoveStrategy.java
+24
-0
SqlExpActuator.java
...rc/main/java/org/matrix/actuators/sql/SqlExpActuator.java
+43
-4
Action.java
kt-base/src/main/java/org/matrix/database/entity/Action.java
+3
-2
IActionService.java
...main/java/org/matrix/database/service/IActionService.java
+4
-0
ActionServiceImpl.java
...a/org/matrix/database/service/impl/ActionServiceImpl.java
+19
-1
DynamicVariableServiceImpl.java
...rix/database/service/impl/DynamicVariableServiceImpl.java
+1
-1
ActionType.java
kt-base/src/main/java/org/matrix/enums/ActionType.java
+43
-0
BeanFlattener.java
kt-base/src/main/java/org/matrix/util/BeanFlattener.java
+69
-0
没有找到文件。
kt-base/src/main/java/org/matrix/actuators/httpclient/HttpResponseDetail.java
浏览文件 @
f38e0b2e
...
...
@@ -3,6 +3,7 @@ package org.matrix.actuators.httpclient;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
import
lombok.NoArgsConstructor
;
import
org.apache.http.client.methods.CloseableHttpResponse
;
import
org.matrix.actuators.usecase.BaseTestCaseResponseDetail
;
...
...
@@ -11,6 +12,7 @@ import org.springframework.http.HttpStatus;
/**
* @author huangxiahao
*/
@EqualsAndHashCode
(
callSuper
=
true
)
@Data
@AllArgsConstructor
@NoArgsConstructor
...
...
kt-base/src/main/java/org/matrix/actuators/move/MoveActuator.java
0 → 100644
浏览文件 @
f38e0b2e
package
org
.
matrix
.
actuators
.
move
;
import
com.alibaba.fastjson.JSON
;
import
com.google.common.collect.Lists
;
import
lombok.AllArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.matrix.actuators.Actuator
;
import
org.matrix.actuators.httpclient.HttpClientActuator
;
import
org.matrix.actuators.httpclient.HttpRequestDetail
;
import
org.matrix.actuators.httpclient.HttpResponseDetail
;
import
org.matrix.actuators.sql.SqlExpActuator
;
import
org.matrix.actuators.sql.SqlExpDetail
;
import
org.matrix.actuators.usecase.CaseActuator
;
import
org.matrix.actuators.util.CompleteExpressionUtil
;
import
org.matrix.database.entity.Action
;
import
org.matrix.database.entity.TestCaseBTO
;
import
org.matrix.database.service.ITestDataService
;
import
org.matrix.database.service.impl.ActionServiceImpl
;
import
org.matrix.enums.ActionType
;
import
org.matrix.exception.GlobalException
;
import
org.matrix.util.BeanFlattener
;
import
org.springframework.stereotype.Component
;
import
java.util.*
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
java.util.stream.Collectors
;
import
static
org
.
matrix
.
actuators
.
move
.
MoveStrategy
.*;
import
static
org
.
matrix
.
enums
.
ActionType
.*;
/**
* MoveActuator.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/2/25 at 3:32 PM
* Suffering is the most powerful teacher of life.
*/
@SuppressWarnings
(
"AlibabaLowerCamelCaseVariableNaming"
)
@Slf4j
@Component
@AllArgsConstructor
public
class
MoveActuator
implements
Actuator
{
/**
* 识别行为语法的正则字符串
*/
private
static
final
String
MOVE_POOL_REG
=
"\\$\\{(?<col>[\\w|.]*)}(\\[(?<row>\\d*)])?(?<jp><(\\s)*\\$.*?>)?"
;
private
static
final
List
<
String
>
STRATEGY_LIST
=
Arrays
.
asList
(
PRE_MOVE
.
name
(),
MID_MOVE
.
name
(),
AFT_MOVE
.
name
());
private
final
CompleteExpressionUtil
resultUtil
;
private
final
ActionServiceImpl
actionService
;
private
final
SqlExpActuator
sqlExpActuator
;
private
final
HttpClientActuator
httpActuator
;
private
final
ITestDataService
dataService
;
private
final
CaseActuator
caseActuator
;
private
final
CompleteExpressionUtil
expressionUtil
;
/**
* 动作临时结果保存的的ThreadLocal的结果集保存,key = strategy_actionId (例如PRE_MOVE_1),value 是 数据表,如果存在则add,如果不存在则put
*/
private
ThreadLocal
<
Map
<
String
,
List
<
Map
<
String
,
Object
>>>>
resSet
=
ThreadLocal
.
withInitial
(
HashMap:
:
new
);
/**
* 将含有动作结果池语法 ${pre1.name}[0]<$.book> 这样的语法 ${a}[b]<c>
* 其中a是定位列,b是定位行数,c是内容的二次JSON解析
* 可能出现的情况是
* <blockquote>
* <pre>
* a -> 默认第一行,直接返回某个列的数据
* ab -> 第a列第b行,直接返回
* ac -> 第a列第一行,取到的数据用c去解析
* abc -> 第a列第b行,取到的数据用c去解析
* </pre>
* </blockquote>
*
* @param dynamicString 含有动作结果池的字段 ${pre1.name}[0]<$.book> 简写就是 ${a}[b]<c>
* @return 找出动作结果池语法里其中的变量名与对应的下标序列值(默认为0)
*/
public
String
parseMoveVar
(
String
dynamicString
)
{
Pattern
pattern
=
Pattern
.
compile
(
MOVE_POOL_REG
);
Matcher
matcher
=
pattern
.
matcher
(
dynamicString
);
String
col
,
row
,
jsonPath
;
int
rowIndex
;
boolean
pathResolution
;
// 提取、提取、补全 col,row,json_path内容
if
(
matcher
.
find
())
{
col
=
matcher
.
group
(
"col"
);
if
(
StringUtils
.
isEmpty
(
col
))
{
throw
new
GlobalException
(
"动作语法里必须包含形如${pre1.name}这样的字符串!您提供的是: "
+
dynamicString
);
}
row
=
matcher
.
group
(
"row"
);
if
(
StringUtils
.
isEmpty
(
row
))
{
rowIndex
=
0
;
}
else
{
rowIndex
=
Integer
.
parseInt
(
row
);
}
jsonPath
=
matcher
.
group
(
"jp"
);
if
(
StringUtils
.
isEmpty
(
jsonPath
))
{
pathResolution
=
false
;
}
else
{
pathResolution
=
true
;
}
}
else
{
throw
new
GlobalException
(
"提供的语法不正确!正确的语法应当是形如 ${pre1.name}[0]<$.book> 这样的,您提供的是 :"
+
dynamicString
);
}
// 解析,解释 col、row、jp
MoveRegularObject
mro
=
col2RegularObj
(
col
);
List
<
Map
<
String
,
Object
>>
valueMap
=
resSet
.
get
().
get
(
mro
.
getKey
());
if
(
valueMap
.
size
()
<=
rowIndex
)
{
throw
new
GlobalException
(
String
.
format
(
"没有找到指定行的数据,您要求的数据行数为%d,实际存在的数据行数为%d"
,
rowIndex
,
valueMap
.
size
()));
}
String
finalValue
=
null
;
if
(
valueMap
.
get
(
rowIndex
).
get
(
mro
.
getColName
())
==
null
)
{
log
.
warn
(
"[行为执行器] {}语法下的 {} 列 数据为 null"
,
dynamicString
,
mro
.
getColName
());
}
else
{
finalValue
=
valueMap
.
get
(
rowIndex
).
get
(
mro
.
getColName
()).
toString
();
}
// 是否需要继续解析jsonPath
if
(
pathResolution
)
{
finalValue
=
expressionUtil
.
completeJsonPathExpression
(
jsonPath
,
finalValue
);
}
return
finalValue
;
}
/**
* 中间行为执行器,根据运行时环境决定使用哪一个动作,并根据动作的类型调用不同的动作执行器(该方法用于中间动作与后置动作)
* 其中中间动作与后置动作需要进行结果集数据的替换,然后根据动作类型,策略,ID 来制作主键
* key = actionType_strategy_actionId
* 当 动作类型是 SQL 类型时,value = 数据表
* 当 动作类型是 HTTP/CASE 类型时, value = detail对象的属性(key=属性名,value=属性数值)
*
* @param moveId 行为id
* @param envId 环境id
* @param projectId 项目id
* @param caseResultData 测试用例执行后保留下的结果集,该参数在前置策略中可以为null,在中间/后置策略中必须要提供合理的结果集对象
* @param strategy 动作的策略,即是前置/中间/后置,具体查看{@link MoveStrategy}
*/
public
void
runMove
(
Long
moveId
,
Long
envId
,
Long
projectId
,
Object
caseResultData
,
MoveStrategy
strategy
)
{
Action
action
=
actionService
.
findByMoveAndEnv
(
moveId
,
envId
)
.
orElseThrow
(()
->
new
GlobalException
(
String
.
format
(
"没有找到指定的action动作对象,提供查询的moveId = %d,envId = %d"
,
moveId
,
envId
)));
// 如果是 mid 或者 aft 动作,则需要进行结果集的语法替换 与 空值判断
if
(
strategy
!=
PRE_MOVE
)
{
if
(
Objects
.
isNull
(
caseResultData
))
{
throw
new
GlobalException
(
String
.
format
(
"中间与后置动作必须要提供结果集! moveId = %d,envId = %d"
,
moveId
,
envId
));
}
// 尝试解析并替换动作中要用到用例结果集的情况
String
runtimeDetail
=
resultUtil
.
completeJsonPathExpression
(
action
.
getDetail
(),
caseResultData
);
action
.
setDetail
(
runtimeDetail
);
}
// 拼接key,准备数据容器
ActionType
actionType
=
action
.
getType
();
String
runtimeDetail
=
action
.
getDetail
();
String
key
=
Lists
.
newArrayList
(
strategy
,
moveId
)
.
stream
().
map
(
Object:
:
toString
)
.
collect
(
Collectors
.
joining
(
"_"
));
Map
<
String
,
List
<
Map
<
String
,
Object
>>>
res
=
resSet
.
get
();
// 分类处理 + 结果集处理(如果不存在则put数据,如果存在则替换数据)
log
.
info
(
"[动作执行器] 正在执行动作 actionId = {},动作类型 = {},动作策略 = {},动作参数 = {}"
,
action
.
getId
(),
action
,
strategy
,
runtimeDetail
);
if
(
actionType
==
SQL_ACTION
)
{
List
<
Map
<
String
,
Object
>>
resultMap
=
sqlActionHandler
(
envId
,
projectId
,
runtimeDetail
);
res
.
put
(
key
,
resultMap
);
}
else
if
(
actionType
==
HTTP_ACTION
)
{
res
.
put
(
key
,
Lists
.
newArrayList
(
detail2Map
(
httpActionHandler
(
envId
,
projectId
,
runtimeDetail
))));
}
else
if
(
actionType
==
CASE_ACTION
)
{
res
.
put
(
key
,
Lists
.
newArrayList
(
detail2Map
(
caseActionHandler
(
envId
,
projectId
,
runtimeDetail
))));
}
else
if
(
actionType
==
WAIT_ACTION
)
{
waitActionHandler
(
runtimeDetail
);
}
else
{
throw
new
GlobalException
(
"不支持的行为类型: "
+
actionType
);
}
}
/**
* 清理结果集
*/
public
void
clearMoveRes
()
{
log
.
info
(
"[动作执行器] 清理动作结果池缓存"
);
resSet
=
ThreadLocal
.
withInitial
(
HashMap:
:
new
);
}
/**
* 将行为语法里的col部分转化为threadLocal里的key值
*
* @param col 原始col字符串
* @return threadLocal里的key值
*/
private
MoveRegularObject
col2RegularObj
(
String
col
)
{
String
[]
colArray
=
col
.
split
(
"\\."
);
if
(
colArray
.
length
!=
2
)
{
throw
new
GlobalException
(
"行为语法里定位部分的语法不符合规范,您提供的部分是: "
+
col
);
}
String
strategy
=
colArray
[
0
].
substring
(
0
,
3
).
toUpperCase
()
+
"_MOVE"
;
if
(!
STRATEGY_LIST
.
contains
(
strategy
))
{
throw
new
GlobalException
(
"行为语法里定位部分的语法不符合规范(需要至少包含pre/mid/aft),您提供的部分是:"
+
col
);
}
int
actionId
;
try
{
actionId
=
Integer
.
parseInt
(
colArray
[
0
].
substring
(
3
));
}
catch
(
NumberFormatException
e
)
{
throw
new
GlobalException
(
"行为语法里定位部分的语法没有提供合适的actionId!例如需要提供pre1,pre2,您提供的部分是: "
+
col
);
}
String
key
=
strategy
+
"_"
+
actionId
;
return
new
MoveRegularObject
(
key
,
colArray
[
1
]);
}
/**
* 线程等待执行器
*
* @param runtimeDetail 要等待的时间,单位毫秒ms
*/
private
void
waitActionHandler
(
String
runtimeDetail
)
{
try
{
int
sleepMills
=
Integer
.
parseInt
(
runtimeDetail
);
Thread
.
sleep
(
sleepMills
);
}
catch
(
InterruptedException
e
)
{
log
.
error
(
"[线程异常] 线程休眠时发生异常,异常信息 : "
+
e
.
getMessage
());
}
catch
(
Exception
e
)
{
log
.
error
(
"[参数/转换异常] 执行行为时参数抓换时发生异常,异常信息 "
+
e
.
getMessage
());
}
}
/**
* 用例行为解析器
*
* @param envId 环境ID
* @param projectId 项目ID
* @param runtimeDetail 用例行为解析器
*/
private
HttpResponseDetail
caseActionHandler
(
Long
envId
,
Long
projectId
,
String
runtimeDetail
)
{
long
caseDataId
=
Long
.
parseLong
(
runtimeDetail
);
TestCaseBTO
caseBTO
=
dataService
.
toCaseBTO
(
caseDataId
);
return
(
HttpResponseDetail
)
caseActuator
.
executeTestCase
(
caseBTO
,
envId
,
projectId
)
.
getBaseTestCaseRequestDetail
();
}
/**
* http行为解析器
*
* @param envId 环境ID
* @param projectId 项目ID
* @param runtimeDetail http url 与 参数字符串
*/
private
HttpResponseDetail
httpActionHandler
(
Long
envId
,
Long
projectId
,
String
runtimeDetail
)
{
HttpRequestDetail
httpRequestDetail
=
JSON
.
parseObject
(
runtimeDetail
,
HttpRequestDetail
.
class
);
return
httpActuator
.
sendHttpRequest
(
httpRequestDetail
,
envId
,
projectId
);
}
/**
* SQL动作解析器
*
* @param envId 环境ID
* @param projectId 项目ID
* @param runtimeDetail SQL字符串
*/
private
List
<
Map
<
String
,
Object
>>
sqlActionHandler
(
Long
envId
,
Long
projectId
,
String
runtimeDetail
)
{
SqlExpDetail
sqlExpDetail
=
JSON
.
parseObject
(
runtimeDetail
,
SqlExpDetail
.
class
);
return
sqlExpActuator
.
parseSql
(
sqlExpDetail
,
envId
,
projectId
);
}
private
Map
<
String
,
Object
>
detail2Map
(
HttpResponseDetail
detail
)
{
return
BeanFlattener
.
deepToMap
(
detail
);
}
}
kt-base/src/main/java/org/matrix/actuators/move/MoveRegularObject.java
0 → 100644
浏览文件 @
f38e0b2e
package
org
.
matrix
.
actuators
.
move
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* MoveRegularObject.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/3/7 at 6:24 PM
* Suffering is the most powerful teacher of life.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public
class
MoveRegularObject
{
/**
* 在ThreadLocal里的key值
*/
private
String
key
;
/**
* 要取的字段名
*/
private
String
colName
;
}
kt-base/src/main/java/org/matrix/actuators/move/MoveStrategy.java
0 → 100644
浏览文件 @
f38e0b2e
package
org
.
matrix
.
actuators
.
move
;
/**
* MoveStrategy.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/3/7 at 3:11 PM
* Suffering is the most powerful teacher of life.
*/
public
enum
MoveStrategy
{
/**
* 前置动作
*/
PRE_MOVE
,
/**
* 中间动作
*/
MID_MOVE
,
/**
* 后置动作
*/
AFT_MOVE
;
}
kt-base/src/main/java/org/matrix/actuators/sql/SqlExpActuator.java
浏览文件 @
f38e0b2e
...
...
@@ -45,7 +45,7 @@ import static org.springframework.util.CollectionUtils.isEmpty;
public
class
SqlExpActuator
implements
Actuator
{
/**
* 用于正则找出形如${id}这样的SQL变量
* 用于正则找出形如${id}
或者 ${id}[1]
这样的SQL变量
*/
public
static
final
String
DYNAMIC_VAR_EXP
=
"\\$\\{(\\w*)}\\[?(\\d*)]?"
;
...
...
@@ -62,13 +62,51 @@ public class SqlExpActuator implements Actuator {
private
final
IDynamicVariableService
varService
;
private
final
IConnectService
connectService
;
private
final
IDataSourceService
dataSourceService
;
private
final
ITestCaseService
caseService
;
private
final
ITestDataService
dataService
;
/**
* 解析并运行SQL语句,可以包含别的SQL变量,例如 'select * from user where user.id = ${user_id} '
* @param sqlDetail sql的poolId与sql语句的对象
* @param envId 环境id
* @param projectId 项目id
* @return 运行SQL后取完数值的结果, 是一张数据表, 以LIST<MAP>的形式呈现
*/
public
List
<
Map
<
String
,
Object
>>
parseSql
(
SqlExpDetail
sqlDetail
,
Long
envId
,
Long
projectId
){
// 找到第一层的SQL变量,递归替换
String
sqlExp
=
sqlDetail
.
getSqlExp
();
Long
connectId
=
sqlDetail
.
getPoolId
();
List
<
SqlRegularObject
>
varList
=
findDynamicVarList
(
sqlExp
);
for
(
SqlRegularObject
sqlReg
:
varList
)
{
sqlExp
=
sqlExp
.
replaceAll
(
sqlReg
.
getVarName
(),
parseVarByName
(
sqlReg
.
getVarName
(),
envId
,
projectId
));
}
// 运行SQL
DataSourceDTO
dataSourceDTO
=
Optional
.
of
(
connectService
.
getById
(
connectId
))
.
orElseThrow
(()
->
new
GlobalException
(
String
.
format
(
"没有找到id = %d 的连接池connect对象"
,
connectId
)))
.
toDataSourceDTO
();
// 替换环境共享变量
sqlExp
=
envActuator
.
replaceEnvVar
(
sqlExp
,
envId
);
// 校验dynamicVar里的detail是否是可以直接执行的SQL
boolean
allVarParsed
=
findDynamicVarList
(
sqlExp
).
size
()
==
0
;
if
(
allVarParsed
)
{
// 切换数据源,执行SQL,获取数值
Set
<
String
>
dataSources
=
dataSourceService
.
switchDataSource
(
dataSourceDTO
);
log
.
info
(
"当前存在的数据源 {}"
,
dataSources
);
List
<
Map
<
String
,
Object
>>
resultMap
=
jdbcTemplate
.
queryForList
(
sqlExp
);
dataSourceService
.
switchMainDataSource
();
return
resultMap
;
}
else
{
throw
new
GlobalException
(
String
.
format
(
"SQL解析异常,SQL语句为%s,连接池id为%d"
,
sqlDetail
.
getSqlExp
(),
sqlDetail
.
getPoolId
()));
}
}
/**
* 解析给定的动态变量ByName
*
* @param varNameString 变量名,形如${id}
这样的字符串
* @param varNameString 变量名,形如${id}
或者是 ${id}[1]这样的字符串,默认下标为0
* @param projectId 该变量所在的项目ID
* @return 变量递归解析后的值
*/
...
...
@@ -170,7 +208,8 @@ public class SqlExpActuator implements Actuator {
String
sqlExp
=
dynamicVar
.
getSqlExpDetail
().
getSqlExp
();
sqlExp
=
envActuator
.
replaceEnvVar
(
sqlExp
,
envId
);
List
<
SqlRegularObject
>
dynamicVarList
=
findDynamicVarList
(
dynamicVar
.
getDetail
());
String
detail
=
dynamicVar
.
getDetail
();
List
<
SqlRegularObject
>
dynamicVarList
=
findDynamicVarList
(
detail
);
// 解析SQL表达式,判断是可以直接执行的SQL还是需要再递归解析动态变量
if
(!
isEmpty
(
dynamicVarList
))
{
// 如果还存在动态变量,则继续递归解析
...
...
kt-base/src/main/java/org/matrix/database/entity/Action.java
浏览文件 @
f38e0b2e
...
...
@@ -7,6 +7,7 @@ import lombok.AllArgsConstructor;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
import
lombok.NoArgsConstructor
;
import
org.matrix.enums.ActionType
;
/**
* <p>
...
...
@@ -37,8 +38,8 @@ public class Action extends BaseEntity {
private
String
remark
;
@ApiModelProperty
(
"类型 1为SQL,2为HTTP,3为CASE,4为WAIT_TIME"
)
private
Integer
type
;
private
ActionType
type
;
@ApiModelProperty
(
"详细参数"
)
private
String
detail
;
...
...
kt-base/src/main/java/org/matrix/database/service/IActionService.java
浏览文件 @
f38e0b2e
...
...
@@ -3,6 +3,8 @@ package org.matrix.database.service;
import
org.matrix.database.entity.Action
;
import
com.baomidou.mybatisplus.extension.service.IService
;
import
java.util.Optional
;
/**
* <p>
* 动作 服务类
...
...
@@ -13,4 +15,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public
interface
IActionService
extends
IService
<
Action
>
{
Optional
<
Action
>
findByMoveAndEnv
(
Long
moveId
,
Long
envId
);
}
kt-base/src/main/java/org/matrix/database/service/impl/ActionServiceImpl.java
浏览文件 @
f38e0b2e
package
org
.
matrix
.
database
.
service
.
impl
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.toolkit.Wrappers
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
org.matrix.database.entity.Action
;
import
org.matrix.database.mapper.ActionMapper
;
import
org.matrix.database.service.IActionService
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
org.springframework.stereotype.Service
;
import
java.util.Optional
;
/**
* <p>
* 动作 服务实现类
...
...
@@ -17,4 +21,18 @@ import org.springframework.stereotype.Service;
@Service
public
class
ActionServiceImpl
extends
ServiceImpl
<
ActionMapper
,
Action
>
implements
IActionService
{
private
final
ActionMapper
actionMapper
;
public
ActionServiceImpl
(
ActionMapper
mapper
)
{
this
.
actionMapper
=
mapper
;
}
@Override
public
Optional
<
Action
>
findByMoveAndEnv
(
Long
moveId
,
Long
envId
)
{
LambdaQueryWrapper
<
Action
>
actionWrappers
=
Wrappers
.
lambdaQuery
(
Action
.
class
);
Action
action
=
actionMapper
.
selectOne
(
actionWrappers
.
eq
(
Action:
:
getMoveId
,
moveId
)
.
eq
(
Action:
:
getEnvId
,
envId
));
return
Optional
.
ofNullable
(
action
);
}
}
kt-base/src/main/java/org/matrix/database/service/impl/DynamicVariableServiceImpl.java
浏览文件 @
f38e0b2e
...
...
@@ -35,7 +35,7 @@ public class DynamicVariableServiceImpl extends ServiceImpl<DynamicVariableMappe
*/
@Override
public
Optional
<
DynamicVariable
>
getByName
(
String
name
,
Long
projectId
)
{
return
Optional
.
ofNullable
(
mapper
.
selectOne
(
Wrappers
.
lambda
Update
(
DynamicVariable
.
class
)
return
Optional
.
ofNullable
(
mapper
.
selectOne
(
Wrappers
.
lambda
Query
(
DynamicVariable
.
class
)
.
eq
(
DynamicVariable:
:
getName
,
name
)
.
eq
(
DynamicVariable:
:
getProjectId
,
projectId
)));
}
...
...
kt-base/src/main/java/org/matrix/enums/ActionType.java
0 → 100644
浏览文件 @
f38e0b2e
package
org
.
matrix
.
enums
;
import
com.baomidou.mybatisplus.annotation.EnumValue
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
/**
* ActionType.
* 动作的类型,该变量决定了运行时使用哪一种执行器
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/2/25 at 5:18 PM
* Suffering is the most powerful teacher of life.
*/
@Getter
@AllArgsConstructor
public
enum
ActionType
{
/**
* SQL类型动作,该动作执行SQL语句
*/
SQL_ACTION
(
1
,
"SQL类型动作"
),
/**
* HTTP类型动作,该动作执行HTTP接口
*/
HTTP_ACTION
(
2
,
"HTTP类型动作"
),
/**
* 用例类型动作,该动作执行另外的测试用例
*/
CASE_ACTION
(
3
,
"用例类型动作"
),
/**
* 等待类动作,线程休眠指定的秒数
*/
WAIT_ACTION
(
4
,
"等待类动作"
);
/**
* 数据库里记录的字段使用该字段来记录
*/
@EnumValue
private
final
int
code
;
private
final
String
des
;
}
kt-base/src/main/java/org/matrix/util/BeanFlattener.java
0 → 100644
浏览文件 @
f38e0b2e
package
org
.
matrix
.
util
;
import
java.lang.reflect.Field
;
import
java.lang.reflect.Modifier
;
import
java.util.*
;
/**
* BeanFlattener. javaBean 转对象
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/3/7 at 5:15 PM
* Suffering is the most powerful teacher of life.
*/
public
final
class
BeanFlattener
{
private
BeanFlattener
()
{}
public
static
Map
<
String
,
Object
>
deepToMap
(
Object
bean
)
{
Map
<
String
,
Object
>
map
=
new
LinkedHashMap
<>();
try
{
putValues
(
bean
,
map
,
null
);
}
catch
(
IllegalAccessException
x
)
{
throw
new
IllegalArgumentException
(
x
);
}
return
map
;
}
private
static
void
putValues
(
Object
bean
,
Map
<
String
,
Object
>
map
,
String
prefix
)
throws
IllegalAccessException
{
Class
<?>
cls
=
bean
.
getClass
();
for
(
Field
field
:
cls
.
getDeclaredFields
())
{
if
(
field
.
isSynthetic
()
||
Modifier
.
isStatic
(
field
.
getModifiers
()))
{
continue
;
}
field
.
setAccessible
(
true
);
Object
value
=
field
.
get
(
bean
);
String
key
;
if
(
prefix
==
null
)
{
key
=
field
.
getName
();
}
else
{
key
=
prefix
+
"."
+
field
.
getName
();
}
if
(
isValue
(
value
))
{
map
.
put
(
key
,
value
);
}
else
{
putValues
(
value
,
map
,
key
);
}
}
}
private
static
final
Set
<
Class
<?>>
VALUE_CLASSES
=
Collections
.
unmodifiableSet
(
new
HashSet
<>(
Arrays
.
asList
(
Object
.
class
,
String
.
class
,
Boolean
.
class
,
Character
.
class
,
Byte
.
class
,
Short
.
class
,
Integer
.
class
,
Long
.
class
,
Float
.
class
,
Double
.
class
// etc.
)));
private
static
boolean
isValue
(
Object
value
)
{
return
value
==
null
||
value
instanceof
Enum
<?>
||
VALUE_CLASSES
.
contains
(
value
.
getClass
());
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论