JMeter-SSE响应数据自动化3.0

背景

此次因为多了一些需要过滤排除的错误(数量很少),还需要修改下JMeter的jtl文件输出数据(后续统计数据需要)

所以只涉及到JSR脚本的一些改动(此部分改动并不会影响到JMeter的HTML报告)

改动

主要通过设置JMeter中prev输出数据变量threadName为appName这样的方法,来控制jtl的数据。

prev.setThreadName(vars.get("xxx") + "^" + vars.get("xxx"));

脚本如下:

具体改动可以对比自动化2.0

要注意一些响应信息自带的换行符(\n),可能会影响到后续处理jtl文件的数据,目前用的是将\n更换为"-" 或者 ""

java 复制代码
import org.apache.jmeter.samplers.SampleResult;
import org.json.JSONObject;
import org.json.JSONException;

// 每次脚本执行前需要重置的变量
private void init(){
  // 添加APPID信息
  vars.put("APPID",vars.get("appId"));

  // 每次重置isExist的值,避免上次结果影响本次
  vars.put("isExist", "true");

  // 每次重置断言输出信息
  vars.put("response_type","");
  vars.put("error_msg", "");
  vars.put("actual_msg", "");

  // 设置threadName为appName
  prev.setThreadName(vars.get("appName") + "^" + vars.get("xxx"));

}

// 判断是否是流式响应
private Boolean isStreamingResponse(String response) {
  return response.contains("data: {");
}

// 非流式响应处理,即HTTP请求错误处理
private void errorResponse(String response) {
  log.info("进入errorResponse处理!!!");    
      // 判断是不是json格式的响应,first == { ? 是 : 不是
      response = response.replace("\n","");
      String first = response.substring(0,1);
      if("{".equals(first)) {
          // json格式的错误响应
          jsonErrorResponse(response);
      }else {
          // 非json格式的错误响应
          noJsonErrorResponse(response);
      }
}

// json格式的错误响应处理
private void jsonErrorResponse(String response) throws Exception {
  JSONObject jsonResponse = new JSONObject(response);
  String msg = jsonResponse.get("msg");

  if ("智能体不存在".equals(msg)) {
      setAssertMsg("xxx",msg);
  } else {
      setAssertMsg("服务器错误",msg);
  }
}

// 非json格式的错误响应处理
private void noJsonErrorResponse(String response) throws Exception {
  String mainMag = response.substring(0,response.indexOf("at "));
  setAssertMsg("服务器/其他错误",mainMag);
  
}

// 处理SSE响应数据,以data: 为分隔符,输出结果到String[] 中
private String[] splitResponse(String resp) {
 try {
      return resp.split("data: ");
 }catch(Exception e) {
      log.error("拆分resp为String数组失败!xxx:" + vars.get("appName"));
 }
}

// 获取event信息
private String getEvent(String resp) {
  try {
      String ret = resp.substring(resp.indexOf("\"", 8)+1, resp.indexOf("\"", 12));
      return ret;
  }catch(Exception e) {
      log.error("获取event的字段内容失败!");
      return "Unknow";
  }
}

// 处理event = error 的响应
private void errorResp(String resp) {
  try{
      JSONObject jsonResponse = new JSONObject(resp);
      String errorMsg = jsonResponse.get("message");
      setAssertMsg("xxx",errorMsg);
  }catch(Exception e) {
      log.error("处理 error 响应信息失败");
  }
}

// 判断有无特定target
private Boolean hasTarget(String resp) {
  String targetStr = vars.get("target");
  // 每次执行后重置target,避免影响下次target的值
  vars.put("target", "");
  
  return resp.contains(targetStr);
}

// 断言参数设置
private void setAssertMsg(String response_type,String error_msg){
  vars.put("response_type",response_type);
  vars.put("error_msg", error_msg);
  vars.put("isExist", "false");
}
private void setAssertMsg(String resp){
  //此方法用于无目标值的断言参数设置
  //获取answer中的信息,实际msg
  JSONObject jsonResp = new JSONObject(resp);
  String answer = jsonResp.get("data")
                          .get("outputs")
                          .optString("answer");
  vars.put("response_type","输出结果与预期不符");
  vars.put("actual_msg", answer);
  vars.put("isExist", "false");
}

/**
  正确响应结果
  获取正常响应的最终结果,并设置到ResponseMessage,以供后续使用
*/
private void setTrueResp(String resp){
  //获取answer中的信息,实际msg
  JSONObject jsonResp = new JSONObject(resp);
  String answer = jsonResp.get("data")
                          .get("outputs")
                          .optString("answer");
  String s = answer.replace("\n","-");
  prev.setResponseMessage(s);
  vars.put("isExist", "true");

}

// 是否需要判断 特定target
private Boolean needCheckTarget(String resp) {
  if(vars.get("target") != null || !"".equals(vars.get("target"))) {
      // 有target,需要判断特定target
      return hasTarget(resp);
  }else {
      // 无需判断特定target
      return true;
  }
}

// 过滤器,过滤白名单
private void filter(String resp) {
  try {
      Set<String> whiteSet = vars.getObject("whiteSet");
      String appId = vars.get("APPID");
      if(whiteSet.contains(appId)) {
          vars.put("isExist", "true");
      }else {
          // 非白名单
          errorResp(resp);
      }
  } catch (Exception e) {
      setAssertMsg("过滤器失效!","xxx");
      log.warn("过滤白名单失败!");
  }
}

/**
  每次执行后,处理变量
  避免下次空变量的值 受上次的影响
  变量:mustParam
*/
private void afterHandle(){
  vars.put("mustParam","");
  vars.put("target","");
}


SampleResult prev = ctx.getPreviousResult();

String response = prev.getResponseDataAsString();

// 执行前重置变量
init();

// 判断是不是SSE响应
try {
  if (!isStreamingResponse(response)) {
      // 非SSE响应
      errorResponse(response);
  } else {
      // SSE响应
      // 拆分
      String[] respArray = splitResponse(response);
      // 获取event,进行判断
      String event = getEvent(respArray[respArray.length - 1]);
      if("message_end".equals(event)) {
          // 没有错误,判断 workflow_finished 响应中含有目标字段
          if(needCheckTarget(respArray[respArray.length - 2])){
              setTrueResp(respArray[respArray.length - 2]);
          }else {
              // 无目标字段,更新断言信息
              setAssertMsg(respArray[respArray.length - 2]);
          }
      }else if("error".equals(event)) {
          // 有报错,进入过滤器,过滤白名单
          filter(respArray[respArray.length - 1]);
      }else if("Unknow".equals(event)) {
          // 获取event的字段内容失败!
          setAssertMsg("xxx","xxx");
      }else {
          // 未知错误
          setAssertMsg("xxx!","xxx");
      }
  }
} catch (Exception e) {
  log.error("处理响应失败!", e);
  setAssertMsg("xxx!","xxx");
  prev.setSuccessful(false);
}finally {
  afterHandle();
}
相关推荐
Blossom.1182 小时前
基于多模态大模型的工业质检系统:从AOI到“零样本“缺陷识别的产线实践
运维·人工智能·python·机器学习·自动化·测试用例·知识图谱
usrcnusrcn3 小时前
告别PoE管理盲区:有人物联网工业交换机如何以智能供电驱动工业未来
大数据·网络·人工智能·物联网·自动化
2501_944875513 小时前
潭州软件测试工程师精英培训班零基础就业课
运维·自动化
GAOJ_K3 小时前
滚珠螺杆的内循环与外循环有何差异?
人工智能·科技·机器人·自动化·制造
0思必得03 小时前
[Web自动化] CSS基础概念和介绍
前端·css·python·自动化·html·web自动化
科立分板机源头厂家4 小时前
第52集科立分板机:科立分板机有哪些型号
自动化·分板机·激光分板机·科立分板机·pcb分板机
0思必得07 小时前
[Web自动化] HTML5常见新增标签
前端·python·自动化·html5·web自动化
YJlio7 小时前
桌面工具学习笔记(11.4):BgInfo + Desktops + ZoomIt 组合拳——演示与排障环境一键到位
笔记·学习·自动化
weixin_307779138 小时前
Jenkins Pipeline: Multibranch 插件详解:现代CI/CD的多分支管理利器
运维·开发语言·自动化·jenkins·etl
李星星BruceL8 小时前
Pytest第三章(参考指南1)
python·自动化·pytest