开源测试工具 [jvm-sandbox-repeater 学习笔记][入门使用篇] 4 录制、回放与调试

ELes for PPmoney · October 20, 2019 · 494 hits

本章主要讲述使用在非standalone模式下如何进行录制和回放,以及总结了我在学习过程中的调试的技巧。

系列文章导航:
[jvm-sandbox-repeater 学习笔记][入门使用篇] 1 安装与启动
[jvm-sandbox-repeater 学习笔记][入门使用篇] 2 配置说明
[jvm-sandbox-repeater 学习笔记][入门使用篇] 3 现有接口说明
[jvm-sandbox-repeater 学习笔记][入门使用篇] 4 录制、回放与调试(本文)

4.1 开始录制

当repeater启动成功后,就会自动开始录制采集。

在非standalone模式下,会将录制的结果上发到repeater-console中。

4.2 查看录制记录

repeater-console没有提供可以查看录制记录数据的接口。

如果想要知道更加详细的信息,从3 接口文档的篇章中,只有一个供repeater调用的获取录制记录的接口。在该接口中打断点,即可看到更加详细的录制记录信息。

@Override
public RepeaterResult<String> get(String appName, String traceId) {
Record record = recordMapper.selectByAppNameAndTraceId(appName, traceId);
// 在此处打断点,然后调试中执行SerializerWrapper.hessianDeserialize(record.getWrapperRecord(), RecordModel.class)即可查看详情
if (record == null) {
return RepeaterResult.builder().success(false).message("data not exits").build();
}
return RepeaterResult.builder().success(true).message("operate success").data(record.getWrapperRecord()).build();
}

4.3 执行回放

参考3 接口文档中,用户可以通过传入录制记录appName和traceId触发一个录制的回放。

回放成功的要素是:

1、填写正确的appName、traceId

2、回放时录制回放配置与录制时保持一致。

4.4 查看回放结果

参考3 接口文档中,用户通过回放任务的repeatId获取回放结果。

回放结果解读

以下为回放结果的返回结果示例,想要具体字段说明可以参考3 接口文档

{
"success": true,
"data": {
"repeatId": "192168015073156871042776710028ed",
"finish": true,
"response": "123",
"originResponse": "123",
"diff": [],
"cost": 179,
"traceId": "192168015073156871042791710006ed",
"appName": "redis",
"environment": "local",
"host": "192.168.15.73",
"starTime": "2019-09-17T08:53:47.917+0000",
"endTime": "2019-09-17T08:53:48.096+0000",
"mockInvocations": [
{
"index": 1,
"traceId": "192168015073156871042791710006ed",
"repeatId": "192168015073156871042776710028ed",
"success": true,
"skip": false,
"cost": 11,
"originUri": "mybatis://UPDATE/org.spring.springboot.dao.CityDao.updateCity",
"currentUri": "mybatis://UPDATE/org.spring.springboot.dao.CityDao.updateCity",
"originArgs": [
[
{
"cityName": "温岭市3",
"description": "BYSocket 的家在温岭。",
"id": 1,
"provinceId": 1
}
],
{
"keyProperties": [
"id"
],
"isUseGeneratedKeys": false
}
],
"currentArgs": [
[
{
"cityName": "温岭市3",
"description": "BYSocket 的家在温岭。",
"id": 1,
"provinceId": 1
}
],
{
"keyProperties": [
"id"
],
"isUseGeneratedKeys": false
}
]
},
{
"index": 2,
"traceId": "192168015073156871042791710006ed",
"repeatId": "192168015073156871042776710028ed",
"success": true,
"skip": false,
"cost": 2,
"originUri": "java://redis.clients.jedis.Connection/isConnected~()Z",
"currentUri": "java://redis.clients.jedis.Connection/isConnected~()Z",
"originArgs": [],
"currentArgs": []
}
]
},
"message": "operate success"
}

回放成功判定

回放结果中有一个diff字段,但是官方没有实现,所以使用官方开源版本需要人肉对比。

判断要素可参考以下两点:

  1. 回放结果字段中responseoriginResponse一致,说明本次回放的接口中,返回的接口和录制时返回的结果一致。
  2. 且 mockInvocations中的每一个对象的success都为true,说明执行的每一个mock步骤都执行成功。

PS:diff功能可以自行在repeater-console实现,主要是字符串对比输出差异。

回放失败问题定位

如果发现不满足上述成功条件可以从三个方向协助定位。

  1. 查看mockInvications中的mockInviocation是否都执行成功(success是否为true),如果出现了successfalse的情况,说明是该步骤mock失败导致的失败,可以进一步看看这个mockInvication中的currentArgsoriginArgs是否不一致,如果发现不一致,则需要检查代码逻辑,了解入参如何生成,为啥会不一致。
  2. 如果mockInvications中的mockInviocation都执行成功,reponse和originResponse却不一致,可能是因为代码处理逻辑发生了调整,或者执行回放过程中发生了报错。此时先看自己的代码逻辑在最后一个mockInvocation到返回结果之间的代码逻辑是否有改动导致结果不一致。另外可以借助日志repeater的日志进一步定位,日志地址:~/logs/sandbox/repeater/repeater.log,优先看error类的日志内容。如果info级别不足够定位,可以调整至debug级别进行定位。
  3. 日志也没出错,逻辑也没问题,但是就是回放结果不一致,此时可以看看mockInvocations的数量是否与录制记录的subInvocations数量一致。录制记录的subInvocations的查看方法见本文4.2章节。

4.3 使用过程的调试技巧

在这里总结一下我是用过的repeater的调试技巧,以便后续遇到了问题可以更好地进行定位排查以及解决。

4.3.1 日志

添加日志的技巧

在repeater的调研试用过程之初,我对repeater一窍不通。过程中由于配置出错、使用姿势不对等原因,经常遇到repeater没有按照我预期运行的情况。

那时我还不是很懂调试手段,主要是通过看日志、看源码,在源码报错行的上下文加日志来辅助我定位问题。

添加日志的技巧有四:

  1. 在repeater-plugins、repeater-plugins-core两个包中的代码,都可以直接使用repeater-plugins-core提供的LogUtils来进行日志打印,而不需要重新在类中初始化logger。
  2. 当打印的日志内容涉及一些对象时,可以使用JSONObject.toJSONString(object, SerializerFeature.IgnoreNonFieldGetter)来进行打印,这样可以以json格式输出对象中的详细信息,以及通过SerializerFeature.IgnoreNonFieldGetter参数规避一下序列化失败的情况。
  3. 添加日志之后,需要重新构建repeater并重新挂载repeater才能生效,为了提高效率,建议添加日志时尽量往上下文拓展,尽量一次补全流程中可能需要了解信息的日志。
  4. 调试信息请将日志等级改为debug;而在原文中看到有部分debug日志比较有用时,可以调整成info级别的。

切记:添加日志之后,本地环境需要执行install-local.sh脚本,对repeater重新打包并安装到本地环境才可生效,如何重新打包,可以看1 安装与启动中的1.3章节。

日志定位问题的技巧

在录制回放过程中常遇到的情况以及对应日志的情况,在这里做一个小结。

以下日志没有特殊说明就是指~/logs/sandbox/repeater/repeater.log。

请求后没有生成录制记录

  1. 录制回放配置错误,请求不在录制范围内。debug模式下,会打印日志:event missing sample rule
  2. 调用事件处理出错,:"[Error-0000]-uncaught exception occurred when dispatch event。一般可能会是序列化的错误,可以留意这个日志之后的堆栈信息是否有SerializeException相关字样的信息。
  3. 请求repeater-console保存记录失败:[Error-0000]-broadcast record failed
  4. repeater.log没有异常日志,此时可考虑查看是否是repeater-console保存报错导致。建议检查repeater-console的保存逻辑。

回放结果不一致

  1. mock步骤执行失败:can't find any sub invocation——回放过程中没有在录制记录的子调用中找到这个该mock请求相同的调用,需要查看这一个mock请求在回放应用中的调用关系,了解为何录制是没有录制到这一个子调用。
  2. mock步骤执行失败:find invocation by xxx,but similarity not match——回放过程中在录制记录的子调用中只找到了请求相同的但没有找到参数相同的调用。需要查看不一致的参数有哪些,在回放应用的源码中找到参数生成逻辑,了解为何录制和回放为何对于同一个步骤生成了不一样的参数。
  3. 任何出现serialize相关的error日志都是序列化问题。

4.3.2 断点调试

在开发过程中主要使用的调试手段是以jar包的方式启动应用,添加java远程调试相关参数,并以agent模式启动repeater。

命令可参考jvm-sandbox-repeater代码中的bin/bootstrap.sh中的启动命令。

${JAVA_HOME}/bin/java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 \
-javaagent:${HOME}/sandbox/lib/sandbox-agent.jar=server.port=8820\;server.ip=0.0.0.0 \
-Dapp.name=repeater \
-Dapp.env=daily \
-jar 应用.jar

其中:

  • address字段为调试端口。
  • suspend字段可选ynn代表启动应用过程不中断,运行过程等待远程调试器连接,而y代表调试器就绪后启动暂停,直到有远程调试器连接才继续执行启动。当我们需要调试repeater的初始化过程时,就需要用到y模式。

执行启动命令之后,需要调试repeater,则使用idea打开jvm-sandbox-repeater源码,配置对应端口的远程调试,启动调试,连接上后在控制台打印日志:

Connected to the target VM, address: 'localhost:8000', transport: 'socket'

说明成功连上,可以对repeater进行断点调试了。

发现社区也有一篇关于repeater的调试说明且图文并茂的文章,这里放下传送门

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up