背景
此次因為多了一些需要過濾排除的錯誤(數量很少),還需要修改下JMeter的jtl文件輸出數據(后續統計數據需要)
所以只涉及到JSR腳本的一些改動(此部分改動并不會影響到JMeter的HTML報告)
改動
主要通過設置JMeter中prev輸出數據變量threadName為appName這樣的方法,來控制jtl的數據。
prev.setThreadName(vars.get(“xxx”) + “^” + vars.get(“xxx”));
腳本如下:
具體改動可以對比自動化2.0
要注意一些響應信息自帶的換行符(\n),可能會影響到后續處理jtl文件的數據,目前用的是將\n更換為"-" 或者 “”
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為appNameprev.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中的信息,實際msgJSONObject 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中的信息,實際msgJSONObject 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,需要判斷特定targetreturn hasTarget(resp);}else {// 無需判斷特定targetreturn 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();
}