feat(接口自动化): 导入JMX JDBC类型 数据源处理

This commit is contained in:
fit2-zhao 2021-02-19 15:07:19 +08:00
parent 72351396ae
commit 8f9286252c
8 changed files with 207 additions and 17 deletions

View File

@ -0,0 +1,20 @@
package io.metersphere.api.dto.automation;
import io.metersphere.api.dto.scenario.DatabaseConfig;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
@Getter
@Setter
public class ImportPoolsDTO {
private String envId;
private Boolean isCreate;
private ApiTestEnvironmentWithBLOBs testEnvironmentWithBLOBs;
private Map<String, DatabaseConfig> dataSources;
}

View File

@ -1,10 +1,12 @@
package io.metersphere.api.dto.automation.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
import io.github.ningyu.jmeter.plugin.dubbo.sample.MethodArgument;
import io.github.ningyu.jmeter.plugin.util.Constants;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ImportPoolsDTO;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.assertions.*;
@ -30,13 +32,20 @@ import io.metersphere.api.dto.definition.request.sampler.dubbo.MsRegistryCenter;
import io.metersphere.api.dto.definition.request.timer.MsConstantTimer;
import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.DatabaseConfig;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiScenarioModule;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentExample;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.constants.LoopConstants;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.assertions.*;
import org.apache.jmeter.config.ConfigTestElement;
@ -52,6 +61,7 @@ import org.apache.jmeter.modifiers.JSR223PreProcessor;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
import org.apache.jmeter.protocol.java.sampler.JSR223Sampler;
import org.apache.jmeter.protocol.jdbc.config.DataSourceElement;
import org.apache.jmeter.protocol.jdbc.sampler.JDBCSampler;
import org.apache.jmeter.protocol.tcp.sampler.TCPSampler;
import org.apache.jmeter.save.SaveService;
@ -60,24 +70,26 @@ import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.timers.ConstantTimer;
import org.apache.jorphan.collections.HashTree;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.*;
public class MsJmeterParser extends ScenarioImportAbstractParser {
private final String ENV_NAME = "导入数据环境";
@Override
public ScenarioImport parse(InputStream inputSource, ApiTestImportRequest request) {
try {
Object scriptWrapper = SaveService.loadElement(inputSource);
HashTree testPlan = this.getHashTree(scriptWrapper);
// 优先初始化数据源
preInitPool(request.getProjectId(), testPlan);
MsScenario scenario = new MsScenario();
scenario.setReferenced("REF");
jmterHashTree(testPlan, scenario);
this.projectId = request.getProjectId();
ScenarioImport scenarioImport = new ScenarioImport();
scenarioImport.setData(paseObj(scenario, request));
scenarioImport.setProjectid(request.getProjectId());
@ -157,7 +169,7 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
samplerProxy.setPath(source.getPath());
samplerProxy.setMethod(source.getMethod());
if (source.getUrl() != null) {
samplerProxy.setUrl(source.getUrl().toString());
// samplerProxy.setUrl(source.getUrl().toString());
}
samplerProxy.setId(UUID.randomUUID().toString());
samplerProxy.setType("HTTPSamplerProxy");
@ -238,6 +250,87 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
}
}
/**
* 优先初始化数据池
*/
private void preInitPool(String projectId, HashTree hashTree) {
// 初始化已有数据池
initDataSource(projectId, ENV_NAME);
// 添加当前jmx 中新的数据池
preCreatePool(hashTree);
// 更新数据源
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
if (dataPools.getIsCreate()) {
dataPools.getTestEnvironmentWithBLOBs().setConfig(JSON.toJSONString(dataPools.getDataSources().values()));
environmentService.add(dataPools.getTestEnvironmentWithBLOBs());
} else {
dataPools.getTestEnvironmentWithBLOBs().setConfig(JSON.toJSONString(dataPools.getDataSources().values()));
environmentService.update(dataPools.getTestEnvironmentWithBLOBs());
}
}
private void preCreatePool(HashTree tree) {
for (Object key : tree.keySet()) {
// JDBC 数据池
if (key instanceof DataSourceElement) {
DataSourceElement dataSourceElement = (DataSourceElement) key;
if (dataPools != null && dataPools.getDataSources().containsKey(dataSourceElement.getDataSource())) {
DatabaseConfig config = dataPools.getDataSources().get(dataSourceElement.getDataSource());
DatabaseConfig newConfig = new DatabaseConfig();
BeanUtils.copyBean(newConfig, dataSourceElement);
newConfig.setId(config.getId());
dataPools.getDataSources().put(dataSourceElement.getDataSource(), newConfig);
} else {
DatabaseConfig newConfig = new DatabaseConfig();
BeanUtils.copyBean(newConfig, dataSourceElement);
newConfig.setId(UUID.randomUUID().toString());
dataPools.getDataSources().put(dataSourceElement.getDataSource(), newConfig);
}
}
// 递归子项
HashTree node = tree.get(key);
if (node != null) {
preCreatePool(node);
}
}
}
private ImportPoolsDTO dataPools;
private void initDataSource(String projectId, String name) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentExample example = new ApiTestEnvironmentExample();
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo(name);
List<ApiTestEnvironmentWithBLOBs> environments = environmentService.selectByExampleWithBLOBs(example);
dataPools = new ImportPoolsDTO();
if (CollectionUtils.isNotEmpty(environments)) {
dataPools.setIsCreate(false);
dataPools.setTestEnvironmentWithBLOBs(environments.get(0));
Map<String, DatabaseConfig> dataSources = new HashMap<>();
environments.forEach(environment -> {
if (environment != null && environment.getConfig() != null) {
EnvironmentConfig envConfig = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
if (envConfig != null && CollectionUtils.isNotEmpty(envConfig.getDatabaseConfigs())) {
envConfig.getDatabaseConfigs().forEach(item -> {
dataSources.put(item.getName(), item);
});
}
}
dataPools.setEnvId(environment.getId());
dataPools.setDataSources(dataSources);
});
} else {
dataPools.setIsCreate(true);
ApiTestEnvironmentWithBLOBs apiTestEnvironmentWithBLOBs = new ApiTestEnvironmentWithBLOBs();
apiTestEnvironmentWithBLOBs.setId(UUID.randomUUID().toString());
apiTestEnvironmentWithBLOBs.setName(ENV_NAME);
apiTestEnvironmentWithBLOBs.setProjectId(projectId);
dataPools.setTestEnvironmentWithBLOBs(apiTestEnvironmentWithBLOBs);
}
}
private void convertJDBCSampler(MsJDBCSampler msJDBCSampler, JDBCSampler jdbcSampler) {
msJDBCSampler.setType("JDBCSampler");
msJDBCSampler.setName(jdbcSampler.getName());
@ -303,7 +396,9 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
ResponseAssertion assertion = (ResponseAssertion) key;
assertionRegex.setDescription(assertion.getName());
assertionRegex.setAssumeSuccess(assertion.getAssumeSuccess());
assertionRegex.setExpression(assertion.getTestStrings().getStringValue());
if (assertion.getTestStrings() != null && !assertion.getTestStrings().isEmpty()) {
assertionRegex.setExpression(assertion.getTestStrings().get(0).getStringValue());
}
if (assertion.isTestFieldRequestData()) {
assertionRegex.setSubject("Response Data");
}
@ -333,8 +428,9 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
MsAssertionJSR223 msAssertionJSR223 = new MsAssertionJSR223();
JSR223Assertion jsr223Assertion = (JSR223Assertion) key;
msAssertionJSR223.setName(jsr223Assertion.getName());
msAssertionJSR223.setScript(jsr223Assertion.getScript());
msAssertionJSR223.setScriptLanguage(jsr223Assertion.getScriptLanguage());
msAssertionJSR223.setDesc(jsr223Assertion.getName());
msAssertionJSR223.setScript(jsr223Assertion.getPropertyAsString("script"));
msAssertionJSR223.setScriptLanguage(jsr223Assertion.getPropertyAsString("scriptLanguage"));
assertions.setName(jsr223Assertion.getName());
assertions.getJsr223().add(msAssertionJSR223);
@ -347,6 +443,23 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
}
}
/**
* 把节点对象转成XML不然执行时无法正常转换
*
* @param obj
* @return
*/
public static String objToXml(Object obj) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
SaveService.saveElement(obj, baos);
return baos.toString();
} catch (Exception e) {
e.printStackTrace();
LogUtil.warn("HashTree error, can't log jmx scenarioDefinition");
}
return null;
}
private void jmterHashTree(HashTree tree, MsTestElement scenario) {
for (Object key : tree.keySet()) {
MsTestElement elementNode;
@ -358,7 +471,7 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
scenario.setName(((TestPlan) key).getName());
elementNode = new MsJmeterElement();
elementNode.setName(((TestPlan) key).getName());
((MsJmeterElement) elementNode).setJmeterElement(key);
((MsJmeterElement) elementNode).setJmeterElement(objToXml(key));
}
// 线程组
else if (key instanceof ThreadGroup) {
@ -412,12 +525,12 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
((MsJSR223PreProcessor) elementNode).setScript(jsr223Sampler.getPropertyAsString("script"));
((MsJSR223PreProcessor) elementNode).setScriptLanguage(jsr223Sampler.getPropertyAsString("scriptLanguage"));
}
// 提取参数
// 断言规则
else if (key instanceof ResponseAssertion || key instanceof JSONPathAssertion || key instanceof XPath2Assertion || key instanceof JSR223Assertion || key instanceof DurationAssertion) {
elementNode = new MsAssertions();
convertMsAssertions((MsAssertions) elementNode, key);
}
// 断言规则
// 提取参数
else if (key instanceof RegexExtractor || key instanceof XPath2Extractor || key instanceof JSONPostProcessor) {
elementNode = new MsExtract();
convertMsExtract((MsExtract) elementNode, key);
@ -475,8 +588,9 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
elementNode.setType("JmeterElement");
TestElement testElement = (TestElement) key;
elementNode.setName(testElement.getName());
((MsJmeterElement) elementNode).setJmeterElement(key);
((MsJmeterElement) elementNode).setJmeterElement(objToXml(key));
}
elementNode.setEnable(((TestElement) key).isEnabled());
elementNode.setResourceId(UUID.randomUUID().toString());
elementNode.setId(UUID.randomUUID().toString());
elementNode.setIndex(scenario.getHashTree().size() + 1 + "");

View File

@ -111,8 +111,10 @@ public abstract class MsTestElement {
* todo 公共环境逐层传递如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境
*/
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.hashTree, config);
if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.hashTree, config);
}
}
}

View File

@ -148,6 +148,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
if (StringUtils.isNotBlank(this.getPath()) && !isUrl) {
envPath += this.getPath();
sampler.setPath(envPath);
}
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8"));

View File

@ -2,8 +2,19 @@ package io.metersphere.api.dto.definition.request.unknown;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jorphan.collections.HashTree;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
/**
* 暂时存放所有未知的Jmeter Element对象
@ -14,6 +25,41 @@ import lombok.EqualsAndHashCode;
public class MsJmeterElement extends MsTestElement {
private String type = "JmeterElement";
private Object jmeterElement;
private String jmeterElement;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
try {
InputStream inputSource = getStrToStream(jmeterElement);
if (inputSource != null) {
Object scriptWrapper = SaveService.loadElement(inputSource);
HashTree elementTree = tree;
if (!(scriptWrapper instanceof TestPlan) && !(scriptWrapper instanceof ThreadGroup)) {
elementTree = tree.add(scriptWrapper);
}
if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) {
el.toHashTree(elementTree, el.getHashTree(), config);
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static InputStream getStrToStream(String sInputString) {
if (StringUtils.isNotEmpty(sInputString)) {
try {
ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(sInputString.getBytes());
return tInputStringStream;
} catch (Exception ex) {
ex.printStackTrace();
}
}
return null;
}
}

View File

@ -529,6 +529,7 @@ public class ApiAutomationService {
ParameterConfig config = new ParameterConfig();
config.setConfig(envConfig);
HashTree hashTree = request.getTestElement().generateHashTree(config);
System.out.println(request.getTestElement().getJmx(hashTree));
// 调用执行方法
createScenarioReport(request.getId(), request.getScenarioId(), request.getScenarioName(), ReportTriggerMode.MANUAL.name(), request.getExecuteType(), request.getProjectId(),
SessionUtils.getUserId());

View File

@ -26,6 +26,11 @@ public class ApiTestEnvironmentService {
return apiTestEnvironmentMapper.selectByExampleWithBLOBs(example);
}
public List<ApiTestEnvironmentWithBLOBs> selectByExampleWithBLOBs(ApiTestEnvironmentExample example) {
return apiTestEnvironmentMapper.selectByExampleWithBLOBs(example);
}
public ApiTestEnvironmentWithBLOBs get(String id) {
return apiTestEnvironmentMapper.selectByPrimaryKey(id);
}

View File

@ -14,6 +14,7 @@ export const ELEMENTS = new Map([
['JSR223PostProcessor', []],
['Assertions', []],
['Extract', []],
['JmeterElement', []],
['CustomizeReq', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
])