Commit 80bc7296 authored by 黎博's avatar 黎博

Merge branch 'auto'

parents f1825a5b 844dc279
......@@ -4,15 +4,19 @@ import cn.qg.holmes.common.JsonResult;
import cn.qg.holmes.entity.auto.Interface;
import cn.qg.holmes.service.auto.AutoModuleService;
import cn.qg.holmes.service.auto.InterfaceService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 接口相关controller
......@@ -106,4 +110,90 @@ public class InterfaceController {
}
return JsonResult.buildSuccessResult(interfaceService.removeById(interfaceId));
}
/**
* 解析CURL
* @param code curl代码
* @return
*/
@GetMapping("/curl")
public JsonResult resolutionCurl(@RequestParam String code) {
List<Map<String, String>> headersList = new ArrayList<>();
List<Map<String, String>> parametersList = new ArrayList<>();
Map<String, Object> resultMap = new HashMap<>();
if (code.contains("GET")) {
// 处理GET请求
String getParameters = code.split("\\?")[1];
// 去掉末尾的单引号
getParameters = getParameters.substring(0, getParameters.length()-1);
String[] paramPair = getParameters.split("&");
for (String pair: paramPair) {
String[] pairList = pair.split("=");
Map<String, String> map = new HashMap<>();
map.put("paramsName", pairList[0]);
map.put("paramsValue", pairList[1]);
parametersList.add(map);
}
} else if (code.contains("POST")) {
// 处理POST请求
String headerRegex = "--header '(.*)'";
String parameterDataRegex = "--data-urlencode '(.*)'";
String parameterFormRegex = "--form '(.*)'";
String parameterJsonRegex = "--data-raw '(.*)'";
Pattern headerPattern = Pattern.compile(headerRegex);
Pattern parameterDataPattern = Pattern.compile(parameterDataRegex);
Pattern parameterFormPattern = Pattern.compile(parameterFormRegex);
Pattern parameterJsonPattern = Pattern.compile(parameterJsonRegex, Pattern.DOTALL);
Matcher headerMatcher = headerPattern.matcher(code);
Matcher parameterDataMatcher = parameterDataPattern.matcher(code);
Matcher parameterFormMatcher = parameterFormPattern.matcher(code);
Matcher parameterJsonMatcher = parameterJsonPattern.matcher(code);
while (headerMatcher.find()) {
Map<String, String> headersMap = new HashMap<>();
String headerItem = headerMatcher.group(1);
String[] tempList = headerItem.split(":");
headersMap.put("paramsName", tempList[0].trim());
headersMap.put("paramsValue", tempList[1].trim());
headersList.add(headersMap);
}
while (parameterDataMatcher.find()) {
Map<String, String> parameterMap = new HashMap<>();
String parameterItem = parameterDataMatcher.group(1);
String[] tempList = parameterItem.split("=");
parameterMap.put("paramsName", tempList[0].trim());
if (tempList.length == 2) {
parameterMap.put("paramsValue", tempList[1].trim());
} else {
parameterMap.put("paramsValue", "");
}
parametersList.add(parameterMap);
}
while (parameterFormMatcher.find()) {
Map<String, String> parameterMap = new HashMap<>();
String parameterItem = parameterFormMatcher.group(1);
String[] tempList = parameterItem.split("=");
parameterMap.put("paramsName", tempList[0].trim());
if (tempList.length == 2) {
parameterMap.put("paramsValue", tempList[1].trim());
} else {
parameterMap.put("paramsValue", "");
}
parametersList.add(parameterMap);
}
while (parameterJsonMatcher.find()) {
Map<String, String> parameterMap = new HashMap<>();
String parameterItem = parameterJsonMatcher.group(1);
Map<String, Object> requestMap = JSON.parseObject(parameterItem, Map.class);
for (Map.Entry<String, Object> entry: requestMap.entrySet()) {
parameterMap.put("paramsName", entry.getKey());
parameterMap.put("paramsValue", entry.getValue().toString());
parametersList.add(parameterMap);
}
}
}
resultMap.put("headersList", headersList);
resultMap.put("parametersList", parametersList);
return JsonResult.buildSuccessResult(resultMap);
}
}
package cn.qg.holmes.controller.auto;
import cn.qg.holmes.common.JsonResult;
import cn.qg.holmes.entity.auto.Scene;
import cn.qg.holmes.entity.auto.SceneTestcase;
import cn.qg.holmes.entity.auto.SceneTestcaseUpdateVo;
import cn.qg.holmes.service.auto.AutoModuleService;
import cn.qg.holmes.service.auto.InterfaceService;
import cn.qg.holmes.service.auto.SceneService;
import cn.qg.holmes.service.auto.SceneTestcaseService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@CrossOrigin
......@@ -19,6 +23,9 @@ import java.util.List;
@RequestMapping("/auto/sceneTestcase")
public class SceneTestcaseController {
@Autowired
SceneService sceneService;
@Autowired
SceneTestcaseService sceneTestcaseService;
......@@ -39,7 +46,12 @@ public class SceneTestcaseController {
return JsonResult.buildErrorStateResult("请传入场景id", false);
}
List<SceneTestcase> sceneTestcaseList = sceneTestcaseService.getSceneTestcaseListBySceneId(sceneId);
return JsonResult.buildSuccessResult(sceneTestcaseList);
Scene scene = sceneService.getById(sceneId);
Map<String, Object> map = new HashMap<>();
map.put("sceneId", scene.getId());
map.put("globalParameters", scene.getGlobalParameters());
map.put("sceneTestcaseList", sceneTestcaseList);
return JsonResult.buildSuccessResult(map);
}
/**
......@@ -92,6 +104,10 @@ public class SceneTestcaseController {
public JsonResult saveOrUpdateSceneTestcaseList(@RequestBody SceneTestcaseUpdateVo sceneTestcaseUpdateVo) {
List<SceneTestcase> sceneTestcaseList = sceneTestcaseUpdateVo.getSceneTestcaseList();
Integer sceneId = sceneTestcaseUpdateVo.getSceneId();
String globalParameters = sceneTestcaseUpdateVo.getGlobalParameters();
Scene scene = sceneService.getById(sceneId);
scene.setGlobalParameters(globalParameters);
sceneService.saveOrUpdate(scene);
log.info("开始批量修改场景id为 {} 的场景用例:\n {}", sceneId, sceneTestcaseList);
List<SceneTestcase> sceneTestcaseListInDB = sceneTestcaseService.getSceneTestcaseListBySceneId(sceneId);
log.info("数据库中的场景用例为:{}", sceneTestcaseListInDB);
......
......@@ -20,6 +20,7 @@ public class Scene {
private Integer id;
private String name;
private Integer projectId;
private String globalParameters;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
......
......@@ -7,5 +7,6 @@ import java.util.List;
@Data
public class SceneTestcaseUpdateVo {
Integer sceneId;
String globalParameters;
List<SceneTestcase> sceneTestcaseList;
}
......@@ -6,13 +6,15 @@ import java.util.UUID;
public interface AutoUtilsService {
Map<String, String> replaceHeaders(String headers, String variables, UUID uuid);
boolean extractResponse(String response, String extract, UUID uuid);
Map<String, String> replaceParameters(String parameters, String variables, UUID uuid);
Map<String, Object> extractResponseNew(String response, String extract);
Map<String, String> replaceVariables(String parameters, UUID uuid);
boolean extractResponse(String response, String extract, UUID uuid);
Map<String, String> replaceVariablesNew(String parameters, Map<String, Object> globalMap);
boolean assertResponse(String response, List<Map> validateList);
Map<String, Object> handlePreCondition(String namespace, String preString, Map<String, Object> globalMap);
}
package cn.qg.holmes.service.auto.impl;
import cn.qg.holmes.service.auto.AutoUtilsService;
import cn.qg.holmes.utils.HttpClientUtils;
import cn.qg.holmes.utils.RedisUtils;
import com.alibaba.fastjson.JSON;
import com.jayway.jsonpath.JsonPath;
......@@ -8,6 +9,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
......@@ -26,58 +28,38 @@ public class AutoUtilsServiceImpl implements AutoUtilsService {
RedisUtils redisUtils;
/**
* 将请求headers中的变量替换成对应的值
* @param headers 请求头json
* @param variables 参数json
* @return
*/
public Map<String, String> replaceHeaders(String headers, String variables, UUID uuid) {
log.info("开始执行请求头替换!");
Map<String, String> headersMap = JSON.parseObject(headers, Map.class);
Map<String, String> varMap = JSON.parseObject(variables, Map.class);
log.info("替换之前的headers:{}", headersMap);
log.info("参数列表:{}", varMap);
for (String key: varMap.keySet()) {
String value = varMap.get(key);
headersMap.put(key, redisUtils.get(uuid + "_" + value.substring(1)).toString());
}
log.info("替换之后的headers:{}", headersMap);
return headersMap;
}
/**
* 将请求体中的变量替换成对应的值
* @param parameters 请求参数json
* @param variables 变量json
* @return 替换后的参数Map
* 参数替换-新
* @param parameters headers或者parameters
* @param uuid 唯一标识
*/
public Map<String, String> replaceParameters(String parameters, String variables, UUID uuid) {
log.info("开始执行请求参数替换!");
@Override
public Map<String, String> replaceVariables(String parameters, UUID uuid) {
Map<String, String> parameterMap = JSON.parseObject(parameters, Map.class);
Map<String, String> varMap = JSON.parseObject(variables, Map.class);
log.info("替换之前的参数:{}", parameterMap);
log.info("参数列表:{}", varMap);
for (String key: varMap.keySet()) {
String value = varMap.get(key);
parameterMap.put(key, redisUtils.get(uuid + "_" + value.substring(1)).toString());
for (String key: parameterMap.keySet()) {
String value = parameterMap.get(key);
if (value.startsWith("$")) {
parameterMap.put(key, redisUtils.get(uuid + "_" + value.substring(1)).toString());
}
}
log.info("替换之后的参数:{}", parameterMap);
return parameterMap;
}
/**
* 参数替换-新
* @param parameters headers或者parameters
* @param uuid 唯一标识
* 新的参数替换,不再从redis里取值,而是从全局Map中取值
* @param parameters
* @param globalMap
* @return
*/
@Override
public Map<String, String> replaceVariables(String parameters, UUID uuid) {
public Map<String, String> replaceVariablesNew(String parameters, Map<String, Object> globalMap) {
Map<String, String> parameterMap = JSON.parseObject(parameters, Map.class);
log.info("替换之前的参数:{}", parameterMap);
for (String key: parameterMap.keySet()) {
String value = parameterMap.get(key);
if (value.startsWith("$")) {
parameterMap.put(key, redisUtils.get(uuid + "_" + value.substring(1)).toString());
parameterMap.put(key, globalMap.get(value.substring(1)).toString());
}
}
log.info("替换之后的参数:{}", parameterMap);
......@@ -119,6 +101,35 @@ public class AutoUtilsServiceImpl implements AutoUtilsService {
return true;
}
@Override
public Map<String, Object> extractResponseNew(String response, String extract) {
Map<String, Object> resultMap = new HashMap<>();
try {
Map<String, String> extractMap = JSON.parseObject(extract, Map.class);
for (String key: extractMap.keySet()) {
String value = extractMap.get(key);
String extractValue = "";
// 如果以$开头,则使用JsonPath解析
if (value.startsWith("$")) {
extractValue = JsonPath.read(response, value);
} else {
Pattern pattern = Pattern.compile(value);
Matcher matcher = pattern.matcher(response);
if (matcher.find()) {
extractValue = matcher.group(1);
} else {
return null;
}
}
resultMap.put(key, extractValue);
}
return resultMap;
} catch (Exception e) {
e.printStackTrace();
return resultMap;
}
}
/**
* 响应断言
* @return
......@@ -136,6 +147,65 @@ public class AutoUtilsServiceImpl implements AutoUtilsService {
return true;
}
/**
*
* @param namespace
* @param preString
* @return
*/
@Override
public Map<String, Object> handlePreCondition(String namespace, String preString, Map<String, Object> globalMap) {
log.info("开始处理前置动作!");
Map<String, Object> resultMap = new HashMap<>();
try {
List<Map> preList = JSON.parseArray(preString, Map.class);
for (Map<String, Object> map: preList) {
String db = map.get("db").toString();
String sql = map.get("sql").toString();
String key = null;
String type = null;
if (map.get("key") != null) {
key = map.get("key").toString();
}
if (map.get("type") != null) {
type = map.get("type").toString();
}
// 确认SQL中是否需要变量替换
String regex = "(\\{\\{[A-Za-z0-9]+}})";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(sql);
while (matcher.find()) {
String replace = matcher.group();
// 去掉首位的{{和}}
String tempKey = replace.substring(2, replace.length() -2);
sql = sql.replace(replace, "'" + globalMap.get(tempKey).toString() + "'");
}
Map<String, String> params = new HashMap<>();
params.put("namespace", namespace);
params.put("database", db);
params.put("sql", sql);
params.put("type", type);
String url = "https://qa-platform-yxm.liangkebang.net/sql/execute";
String result = HttpClientUtils.doGet(url, params);
log.info("开始执行SQL:{}", sql);
log.info("SQL返回结果:{}", result);
// 只有select才需要加入Map
if (sql.startsWith("select") || sql.startsWith("SELECT")) {
if (type.equals("map")) {
resultMap.put(key, JsonPath.read(result, "$.data." + key));
} else if (type.equals("list")) {
resultMap.put(key, JsonPath.read(result, "$.data."));
}
}
}
log.info("前置动作获取到的值:{}", resultMap);
return resultMap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
*
* @param comparator
......
......@@ -47,16 +47,41 @@ public class SceneTestcaseServiceImpl extends ServiceImpl<SceneTestcaseMapper, S
@Autowired
SceneService sceneService;
/**
* 执行场景用例
* @param namespace 环境
* @param sceneId 场景id
* @param batch 批次号
* @return
*/
@Override
public String executeSceneTestcase(String namespace, Integer sceneId, String batch) {
UUID uuid = UUID.randomUUID();
QueryWrapper queryWrapper = new QueryWrapper();
QueryWrapper<SceneTestcase> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("scene_id", sceneId);
queryWrapper.orderByAsc("sequence");
List<SceneTestcase> sceneTestcaseList = sceneTestcaseMapper.selectList(queryWrapper);
List<Map<String, Object>> resultList = new ArrayList<>();
String globalParameters = sceneService.getById(sceneId).getGlobalParameters();
// 全局变量Map
Map<String, Object> globalMap = new HashMap<>();
if (globalParameters != null) {
globalMap.putAll(JSON.parseObject(globalParameters, Map.class));
}
for (SceneTestcase sceneTestcase: sceneTestcaseList) {
resultList.add(JSON.parseObject(sceneTestcaseExecution(namespace, sceneId, sceneTestcase.getInterfaceId(), sceneTestcase.getSequence(), uuid, batch), Map.class));
String preAction = sceneTestcase.getPreAction();
if (preAction != null && !preAction.isEmpty()) {
Map<String, Object> preMap = autoUtilsService.handlePreCondition(namespace, preAction, globalMap);
if (preMap != null) {
globalMap.putAll(preMap);
}
}
// resultList.add(JSON.parseObject(sceneTestcaseExecution(namespace, sceneId, sceneTestcase.getInterfaceId(), sceneTestcase.getSequence(), uuid, batch), Map.class));
Map<String, Object> tempMap = sceneTestcaseExecution(namespace, sceneId, sceneTestcase.getInterfaceId(), sceneTestcase.getSequence(), batch, globalMap);
Map<String, Object> reportMap = (Map<String, Object>) tempMap.get("report");
Map<String, Object> extractMap = (Map<String, Object>) tempMap.get("extract");
resultList.add(reportMap);
// 将解析出来的值放入全局变量Map
globalMap.putAll(extractMap);
}
return JSON.toJSONString(resultList);
}
......@@ -71,7 +96,7 @@ public class SceneTestcaseServiceImpl extends ServiceImpl<SceneTestcaseMapper, S
return sceneTestcaseMapper.getSceneTestcaseListBySceneId(sceneId);
}
public String sceneTestcaseExecution(String namespace, Integer sceneId, Integer interfaceId, Integer sequence, UUID uuid, String batch) {
public Map<String, Object> sceneTestcaseExecution(String namespace, Integer sceneId, Integer interfaceId, Integer sequence, String batch, Map<String, Object> globalMap) {
QueryWrapper<SceneTestcase> queryWrapper = new QueryWrapper();
queryWrapper.eq("scene_id", sceneId);
queryWrapper.eq("interface_id", interfaceId);
......@@ -91,19 +116,13 @@ public class SceneTestcaseServiceImpl extends ServiceImpl<SceneTestcaseMapper, S
String validate = sceneTestcase.getValidate();
Map<String, String> parameterMap = JSON.parseObject(parameters, Map.class);
Map<String, String> headersMap = JSON.parseObject(headers, Map.class);
// 使用变量替换headers
// if (variables != null && !variables.isEmpty() && headers != null && !headers.isEmpty()) {
// headersMap = autoUtilsService.replaceHeaders(headers, variables, uuid);
// }
if (headers != null && !headers.isEmpty()) {
headersMap = autoUtilsService.replaceVariables(headers, uuid);
// headersMap = autoUtilsService.replaceVariables(headers, uuid);
headersMap = autoUtilsService.replaceVariablesNew(headers, globalMap);
}
// 使用变量替换参数
// if (variables != null && !variables.isEmpty() && parameters != null && !parameters.isEmpty()) {
// parameterMap = autoUtilsService.replaceParameters(parameters, variables, uuid);
// }
if (parameters != null && !parameters.isEmpty()) {
parameterMap = autoUtilsService.replaceVariables(parameters, uuid);
// parameterMap = autoUtilsService.replaceVariables(parameters, uuid);
parameterMap = autoUtilsService.replaceVariablesNew(parameters, globalMap);
}
// 创建断言列表
List<Map> validateList = new ArrayList<>();
......@@ -137,17 +156,23 @@ public class SceneTestcaseServiceImpl extends ServiceImpl<SceneTestcaseMapper, S
assertResult = autoUtilsService.assertResponse(response, validateList);
}
// 解析响应
Map<String, Object> extractMap = new HashMap<>();
if (extract != null && !extract.isEmpty()) {
autoUtilsService.extractResponse(response, extract, uuid);
// autoUtilsService.extractResponse(response, extract, uuid);
extractMap = autoUtilsService.extractResponseNew(response, extract);
}
Map<String, Object> reportMap = new HashMap<>();
reportMap.put("url", url);
reportMap.put("name", interfaceName);
reportMap.put("headers", headersMap);
reportMap.put("parameters", parameterMap);
reportMap.put("assertResult", assertResult);
reportMap.put("elapsedTime", elapsedTime);
try {
reportMap.put("response", JSON.parseObject(response, Map.class));
} catch (Exception e) {
reportMap.put("response", response);
}
Map<String, Object> map = new HashMap<>();
map.put("url", url);
map.put("name", interfaceName);
map.put("headers", headersMap);
map.put("parameters", parameterMap);
map.put("assertResult", assertResult);
map.put("response", JSON.parseObject(response, Map.class));
map.put("elapsedTime", elapsedTime);
// 插入测试报告
SceneTestcaseReport sceneTestcaseReport = new SceneTestcaseReport();
......@@ -173,7 +198,10 @@ public class SceneTestcaseServiceImpl extends ServiceImpl<SceneTestcaseMapper, S
sceneTestcaseReport.setNamespace(namespace);
log.info("保存测试报告:{}", sceneTestcaseReport);
sceneTestcaseReportService.save(sceneTestcaseReport);
return JSON.toJSONString(map);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("report", reportMap);
resultMap.put("extract", extractMap);
return resultMap;
}
}
......@@ -8,6 +8,8 @@ import org.joda.time.DateTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 钉钉发送消息类
......@@ -224,9 +226,21 @@ public class DingdingUtils {
// String markdown = buildMarkdownMsg("YXM-1499", "【羊小咩v7.6.00】【VCC首次交易率提升专题】巴拉巴拉", "黎博", "于巧玲", "p1", "kddsp");
// String markdown = buildPipelineMarkdownMsg("holmes", "master", "bo.li", "测试", "2021-06-03 14:59:45", "fe");
// sendToDingding(markdown, "https://oapi.dingtalk.com/robot/send?access_token=835663338d638e40daaf3ab358af741ef0680a826a962c91bedc53b149d85ee1");
String str = "2021-06-03T09:23:00Z";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String commitDate = simpleDateFormat.format(DateTime.parse(str).toDate());
System.out.println(commitDate);
// String str = "2021-06-03T09:23:00Z";
// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// String commitDate = simpleDateFormat.format(DateTime.parse(str).toDate());
// System.out.println(commitDate);
String model = "(\\{\\{[A-Za-z0-9]+}})";
String sql = "select * from vcc_talos.risk_record where uuid={{uuid}} and userId={{userId}}";
Pattern pattern = Pattern.compile(model);
Matcher matcher = pattern.matcher(sql);
while (matcher.find()) {
String replace = matcher.group();
// 去掉首位的{{和}}
String tempKey = replace.substring(2, replace.length() -2);
sql = sql.replace(replace, "'" + "1234" + "'");
}
System.out.println(sql);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment