fix(接口自动化): 部分缺陷修复

This commit is contained in:
fit2-zhao 2021-04-28 17:19:06 +08:00 committed by fit2-zhao
parent 4318d56a83
commit 14810d24f7
9 changed files with 111 additions and 46 deletions

View File

@ -206,6 +206,7 @@ public abstract class MsTestElement {
}
csvDataSet.setIgnoreFirstLine(false);
csvDataSet.setRecycle(true);
csvDataSet.setProperty("shareMode","shareMode.thread");
csvDataSet.setProperty("recycle", true);
csvDataSet.setProperty("delimiter", item.getDelimiter());
csvDataSet.setComment(StringUtils.isEmpty(item.getDescription()) ? "" : item.getDescription());

View File

@ -111,8 +111,16 @@ public class MsJDBCSampler extends MsTestElement {
this.dataSource = config.getConfig().get(this.getProjectId()).getDatabaseConfigs().get(0);
}
}
if (this.dataSource == null) {
MSException.throwException("数据源为空无法执行");
// 用自身的数据
if (StringUtils.isNotEmpty(dataSourceId)) {
this.dataSource = null;
this.initDataSource();
}
if (this.dataSource == null) {
MSException.throwException("数据源为空无法执行");
}
}
final HashTree samplerHashTree = tree.add(jdbcSampler(config));
tree.add(jdbcDataSource());

View File

@ -21,6 +21,7 @@ import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.parse.ApiImportParser;
import io.metersphere.api.service.task.ParallelExecTask;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
@ -57,6 +58,8 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
@Service
@ -743,6 +746,8 @@ public class ApiAutomationService {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
String reportId = request.getId();
Map<String, HashTree> map = new LinkedHashMap<>();
// 按照场景执行
for (ApiScenarioWithBLOBs item : apiScenarios) {
if (item.getStepTotal() == null || item.getStepTotal() == 0) {
@ -780,11 +785,18 @@ public class ApiAutomationService {
batchMapper.insert(report);
// 调用执行方法
jMeterService.runDefinition(report.getId(), hashTree, request.getReportId(), request.getRunMode());
// jMeterService.runDefinition(report.getId(), hashTree, request.getReportId(), request.getRunMode());
map.put(report.getId(), hashTree);
// 重置报告ID
reportId = UUID.randomUUID().toString();
}
sqlSession.flushStatements();
// 开始执行
ExecutorService executorService = Executors.newFixedThreadPool(map.size());
for (String key : map.keySet()) {
executorService.submit(new ParallelExecTask(jMeterService, key, map.get(key), request));
}
return request.getId();
}
@ -884,7 +896,7 @@ public class ApiAutomationService {
// 生成集成报告
if (request.getConfig() != null && request.getConfig().getMode().equals("serial") && StringUtils.isNotEmpty(request.getConfig().getReportName())) {
request.getConfig().setReportId(UUID.randomUUID().toString());
APIScenarioReportResult report = createScenarioReport(request.getConfig().getReportId(), JSON.toJSONString(reportList), request.getConfig().getReportName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
APIScenarioReportResult report = createScenarioReport(request.getConfig().getReportId(), JSON.toJSONString(reportList), request.getConfig().getReportName(), ReportTriggerMode.MANUAL.name(),
ExecuteType.Saved.name(), request.getProjectId(), request.getReportUserID(), request.getConfig());
batchMapper.insert(report);
}

View File

@ -361,7 +361,6 @@ public class ApiScenarioReportService {
} else {
report.setUserId(SessionUtils.getUserId());
}
report.setTriggerMode(runMode);
report.setExecuteType(ExecuteType.Saved.name());
report.setProjectId(projectId);
report.setScenarioName(scenarioNames.toString().substring(0, scenarioNames.toString().length() - 1));

View File

@ -0,0 +1,38 @@
/**
*
*/
package io.metersphere.api.service.task;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import org.apache.jorphan.collections.HashTree;
import java.util.concurrent.Callable;
public class ParallelExecTask<T> implements Callable<T> {
private RunScenarioRequest request;
private JMeterService jMeterService;
private HashTree hashTree;
private String id;
public ParallelExecTask(JMeterService jMeterService, String id, HashTree hashTree, RunScenarioRequest request) {
this.jMeterService = jMeterService;
this.request = request;
this.hashTree = hashTree;
this.id = id;
}
@Override
public T call() {
try {
jMeterService.runDefinition(id, hashTree, request.getReportId(), request.getRunMode());
return null;
} catch (Exception ex) {
LogUtil.error(ex.getMessage());
MSException.throwException(ex.getMessage());
return null;
}
}
}

View File

@ -84,6 +84,8 @@ public class JSONSchemaGenerator {
JsonObject propertyObj = propertiesObj.get(propertyKey).getAsJsonObject();
analyzeProperty(rootObj, propertyKey, propertyObj);
}
} else if (object.has("type") && object.get("type").getAsString().equals("array")) {
analyzeProperty(rootObj, "MS-OBJECT", object);
} else if (object.has("type") && !object.get("type").getAsString().equals("object")) {
analyzeProperty(rootObj, object.getAsString(), object);
}
@ -298,6 +300,9 @@ public class JSONSchemaGenerator {
generator(jsonSchema, root);
// 格式化返回
Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
if (root.get("MS-OBJECT") != null) {
return gson.toJson(root.get("MS-OBJECT"));
}
return gson.toJson(root);
} else {
return report.getExceptionThreshold().toString();

View File

@ -45,7 +45,7 @@
:request="request"
:showScript="false"/>
<ms-sql-basis-parameters v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'"
:request="request" :is-scenario="true" :environment="environment"
:request="request" :is-scenario="false" :environment="environment"
:showScript="false"/>
<ms-dubbo-basis-parameters v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'"
:request="request"

View File

@ -1,11 +1,11 @@
const isBoolean = require("lodash.isboolean")
const isEmpty = require("lodash.isempty")
const isInteger = require("lodash.isinteger")
const isNull = require("lodash.isnull")
const isNumber = require("lodash.isnumber")
const isObject = require("lodash.isobject")
const isString = require("lodash.isstring")
const isArray = Array.isArray
const isBoolean = require("lodash.isboolean");
const isEmpty = require("lodash.isempty");
const isInteger = require("lodash.isinteger");
const isNull = require("lodash.isnull");
const isNumber = require("lodash.isnumber");
const isObject = require("lodash.isobject");
const isString = require("lodash.isstring");
const isArray = Array.isArray;
class Convert {
@ -14,7 +14,7 @@ class Convert {
$id: "http://example.com/root.json",
$schema: "http://json-schema.org/draft-07/schema#",
}
this._object = null
this._object = null;
}
/**
@ -25,22 +25,22 @@ class Convert {
format(object, option = {}) {
// 数据校验确保传入的的object只能是对象或数组
if (!isObject(object)) {
throw new TypeError("传入参数只能是对象或数组")
throw new TypeError("传入参数只能是对象或数组");
}
// 合并属性
this._option = Object.assign(this._option, option)
this._option = Object.assign(this._option, option);
// 需要转换的对象
this._object = object
let convertRes
this._object = object;
let convertRes;
// 数组类型和对象类型结构不一样
if (isArray(object)) {
convertRes = this._arrayToSchema()
convertRes = this._arrayToSchema();
} else {
convertRes = this._objectToSchema()
convertRes = this._objectToSchema();
}
// 释放
this._object = null
return convertRes
this._object = null;
return convertRes;
}
/**
@ -48,16 +48,16 @@ class Convert {
*/
_arrayToSchema() {
// root节点基本信息
let result = this._value2object(this._object, this._option.$id, "", true)
let result = this._value2object(this._object, this._option.$id, "", true);
if (this._object.length > 0) {
// 创建items对象的基本信息
let objectItem = this._object[0]
result["items"] = this._value2object(objectItem, `#/items`, 'items')
result["items"] = this._value2object(objectItem, `#/items`, 'items');
if (isObject(objectItem) && !isEmpty(objectItem)) {
// 递归遍历
let objectItemSchema = this._json2schema(objectItem, `#/items`)
let objectItemSchema = this._json2schema(objectItem, `#/items`);
// 合并对象
result["items"] = Object.assign(result["items"], objectItemSchema)
result["items"] = Object.assign(result["items"], objectItemSchema);
}
}
return result
@ -90,9 +90,9 @@ class Convert {
let result = {};
// 判断传入object是对象还是数组。
if (isArray(object)) {
result.items = {}
result.items = {};
} else {
result.properties = {}
result.properties = {};
}
// 遍历传入的对象
for (const key in object) {
@ -100,7 +100,7 @@ class Convert {
const element = object[key];
// 如果只是undefined。跳过
if (element === undefined) {
continue
continue;
}
let $id = `${name}/properties/${key}`
// 判断当前 element 的值 是否也是对象如果是就继续递归不是就赋值给result
@ -111,22 +111,22 @@ class Convert {
// 针对空数组和有值的数组做不同处理
if (element.length > 0) {
// 如果是数组,那么就取第一项
let elementItem = element[0]
let elementItem = element[0];
// 创建items对象的基本信息
result["properties"][key]["items"] = this._value2object(elementItem, `${$id}/items`, key + 'items')
result["properties"][key]["items"] = this._value2object(elementItem, `${$id}/items`, key + 'items');
// 判断第一项是否是对象,且对象属性不为空
if (isObject(elementItem) && !isEmpty(elementItem)) {
// 新增的properties才合并进来
result["properties"][key]["items"] = Object.assign(result["properties"][key]["items"], this._json2schema(elementItem, `${$id}/items`))
result["properties"][key]["items"] = Object.assign(result["properties"][key]["items"], this._json2schema(elementItem, `${$id}/items`));
}
}
} else {
// 不是数组,递归遍历获取,然后合并对象属性
result["properties"][key] = Object.assign(result["properties"][key], this._json2schema(element, $id))
result["properties"][key] = Object.assign(result["properties"][key], this._json2schema(element, $id));
}
} else {
// 一般属性直接获取基本信息
result["properties"][key] = this._value2object(element, $id, key)
result["properties"][key] = this._value2object(element, $id, key);
}
}
}
@ -150,29 +150,31 @@ class Convert {
// 判断是否为初始化root数据
if (root) {
objectTemplate["$schema"] = this._option.$schema
objectTemplate["title"] = `The Root Schema`
objectTemplate["mock"] = undefined
objectTemplate["$schema"] = this._option.$schema;
objectTemplate["title"] = `The Root Schema`;
objectTemplate["mock"] = undefined;
}
if (isInteger(value)) {
objectTemplate.type = "integer"
objectTemplate.type = "integer";
} else if (isNumber(value)) {
objectTemplate.type = "number"
objectTemplate.type = "number";
} else if (isString(value)) {
objectTemplate.type = "string"
objectTemplate.type = "string";
} else if (isBoolean(value)) {
objectTemplate.type = "boolean"
objectTemplate.type = "boolean";
} else if (isNull(value)) {
objectTemplate.type = "null"
objectTemplate.type = "null";
} else if (isArray(value)) {
objectTemplate.type = "array"
objectTemplate.type = "array";
objectTemplate["mock"] = undefined;
} else if (isObject(value)) {
objectTemplate.type = "object"
objectTemplate["mock"] = undefined;
}
return objectTemplate
return objectTemplate;
}
}
module.exports = Convert
module.exports = Convert;

@ -1 +1 @@
Subproject commit e50f0463826ac4d7837ea3a237333827774a1b19
Subproject commit e7709b9a340394e78610b91105b2cec0f1b8289d