fix(接口自动化): 部分缺陷修复
This commit is contained in:
parent
4318d56a83
commit
14810d24f7
|
@ -206,6 +206,7 @@ public abstract class MsTestElement {
|
||||||
}
|
}
|
||||||
csvDataSet.setIgnoreFirstLine(false);
|
csvDataSet.setIgnoreFirstLine(false);
|
||||||
csvDataSet.setRecycle(true);
|
csvDataSet.setRecycle(true);
|
||||||
|
csvDataSet.setProperty("shareMode","shareMode.thread");
|
||||||
csvDataSet.setProperty("recycle", true);
|
csvDataSet.setProperty("recycle", true);
|
||||||
csvDataSet.setProperty("delimiter", item.getDelimiter());
|
csvDataSet.setProperty("delimiter", item.getDelimiter());
|
||||||
csvDataSet.setComment(StringUtils.isEmpty(item.getDescription()) ? "" : item.getDescription());
|
csvDataSet.setComment(StringUtils.isEmpty(item.getDescription()) ? "" : item.getDescription());
|
||||||
|
|
|
@ -111,8 +111,16 @@ public class MsJDBCSampler extends MsTestElement {
|
||||||
this.dataSource = config.getConfig().get(this.getProjectId()).getDatabaseConfigs().get(0);
|
this.dataSource = config.getConfig().get(this.getProjectId()).getDatabaseConfigs().get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.dataSource == null) {
|
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));
|
final HashTree samplerHashTree = tree.add(jdbcSampler(config));
|
||||||
tree.add(jdbcDataSource());
|
tree.add(jdbcDataSource());
|
||||||
|
|
|
@ -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.dto.scenario.environment.EnvironmentConfig;
|
||||||
import io.metersphere.api.jmeter.JMeterService;
|
import io.metersphere.api.jmeter.JMeterService;
|
||||||
import io.metersphere.api.parse.ApiImportParser;
|
import io.metersphere.api.parse.ApiImportParser;
|
||||||
|
import io.metersphere.api.service.task.ParallelExecTask;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.base.mapper.*;
|
import io.metersphere.base.mapper.*;
|
||||||
import io.metersphere.base.mapper.ext.*;
|
import io.metersphere.base.mapper.ext.*;
|
||||||
|
@ -57,6 +58,8 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -743,6 +746,8 @@ public class ApiAutomationService {
|
||||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||||
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
|
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
|
||||||
String reportId = request.getId();
|
String reportId = request.getId();
|
||||||
|
|
||||||
|
Map<String, HashTree> map = new LinkedHashMap<>();
|
||||||
// 按照场景执行
|
// 按照场景执行
|
||||||
for (ApiScenarioWithBLOBs item : apiScenarios) {
|
for (ApiScenarioWithBLOBs item : apiScenarios) {
|
||||||
if (item.getStepTotal() == null || item.getStepTotal() == 0) {
|
if (item.getStepTotal() == null || item.getStepTotal() == 0) {
|
||||||
|
@ -780,11 +785,18 @@ public class ApiAutomationService {
|
||||||
batchMapper.insert(report);
|
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
|
// 重置报告ID
|
||||||
reportId = UUID.randomUUID().toString();
|
reportId = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
sqlSession.flushStatements();
|
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();
|
return request.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,7 +896,7 @@ public class ApiAutomationService {
|
||||||
// 生成集成报告
|
// 生成集成报告
|
||||||
if (request.getConfig() != null && request.getConfig().getMode().equals("serial") && StringUtils.isNotEmpty(request.getConfig().getReportName())) {
|
if (request.getConfig() != null && request.getConfig().getMode().equals("serial") && StringUtils.isNotEmpty(request.getConfig().getReportName())) {
|
||||||
request.getConfig().setReportId(UUID.randomUUID().toString());
|
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());
|
ExecuteType.Saved.name(), request.getProjectId(), request.getReportUserID(), request.getConfig());
|
||||||
batchMapper.insert(report);
|
batchMapper.insert(report);
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,7 +361,6 @@ public class ApiScenarioReportService {
|
||||||
} else {
|
} else {
|
||||||
report.setUserId(SessionUtils.getUserId());
|
report.setUserId(SessionUtils.getUserId());
|
||||||
}
|
}
|
||||||
report.setTriggerMode(runMode);
|
|
||||||
report.setExecuteType(ExecuteType.Saved.name());
|
report.setExecuteType(ExecuteType.Saved.name());
|
||||||
report.setProjectId(projectId);
|
report.setProjectId(projectId);
|
||||||
report.setScenarioName(scenarioNames.toString().substring(0, scenarioNames.toString().length() - 1));
|
report.setScenarioName(scenarioNames.toString().substring(0, scenarioNames.toString().length() - 1));
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,8 @@ public class JSONSchemaGenerator {
|
||||||
JsonObject propertyObj = propertiesObj.get(propertyKey).getAsJsonObject();
|
JsonObject propertyObj = propertiesObj.get(propertyKey).getAsJsonObject();
|
||||||
analyzeProperty(rootObj, propertyKey, propertyObj);
|
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")) {
|
} else if (object.has("type") && !object.get("type").getAsString().equals("object")) {
|
||||||
analyzeProperty(rootObj, object.getAsString(), object);
|
analyzeProperty(rootObj, object.getAsString(), object);
|
||||||
}
|
}
|
||||||
|
@ -298,6 +300,9 @@ public class JSONSchemaGenerator {
|
||||||
generator(jsonSchema, root);
|
generator(jsonSchema, root);
|
||||||
// 格式化返回
|
// 格式化返回
|
||||||
Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
|
Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
|
||||||
|
if (root.get("MS-OBJECT") != null) {
|
||||||
|
return gson.toJson(root.get("MS-OBJECT"));
|
||||||
|
}
|
||||||
return gson.toJson(root);
|
return gson.toJson(root);
|
||||||
} else {
|
} else {
|
||||||
return report.getExceptionThreshold().toString();
|
return report.getExceptionThreshold().toString();
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
:request="request"
|
:request="request"
|
||||||
:showScript="false"/>
|
:showScript="false"/>
|
||||||
<ms-sql-basis-parameters v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'"
|
<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"/>
|
:showScript="false"/>
|
||||||
<ms-dubbo-basis-parameters v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'"
|
<ms-dubbo-basis-parameters v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'"
|
||||||
:request="request"
|
:request="request"
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
const isBoolean = require("lodash.isboolean")
|
const isBoolean = require("lodash.isboolean");
|
||||||
const isEmpty = require("lodash.isempty")
|
const isEmpty = require("lodash.isempty");
|
||||||
const isInteger = require("lodash.isinteger")
|
const isInteger = require("lodash.isinteger");
|
||||||
const isNull = require("lodash.isnull")
|
const isNull = require("lodash.isnull");
|
||||||
const isNumber = require("lodash.isnumber")
|
const isNumber = require("lodash.isnumber");
|
||||||
const isObject = require("lodash.isobject")
|
const isObject = require("lodash.isobject");
|
||||||
const isString = require("lodash.isstring")
|
const isString = require("lodash.isstring");
|
||||||
const isArray = Array.isArray
|
const isArray = Array.isArray;
|
||||||
|
|
||||||
|
|
||||||
class Convert {
|
class Convert {
|
||||||
|
@ -14,7 +14,7 @@ class Convert {
|
||||||
$id: "http://example.com/root.json",
|
$id: "http://example.com/root.json",
|
||||||
$schema: "http://json-schema.org/draft-07/schema#",
|
$schema: "http://json-schema.org/draft-07/schema#",
|
||||||
}
|
}
|
||||||
this._object = null
|
this._object = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,22 +25,22 @@ class Convert {
|
||||||
format(object, option = {}) {
|
format(object, option = {}) {
|
||||||
// 数据校验,确保传入的的object只能是对象或数组
|
// 数据校验,确保传入的的object只能是对象或数组
|
||||||
if (!isObject(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
|
this._object = object;
|
||||||
let convertRes
|
let convertRes;
|
||||||
// 数组类型和对象类型结构不一样
|
// 数组类型和对象类型结构不一样
|
||||||
if (isArray(object)) {
|
if (isArray(object)) {
|
||||||
convertRes = this._arrayToSchema()
|
convertRes = this._arrayToSchema();
|
||||||
} else {
|
} else {
|
||||||
convertRes = this._objectToSchema()
|
convertRes = this._objectToSchema();
|
||||||
}
|
}
|
||||||
// 释放
|
// 释放
|
||||||
this._object = null
|
this._object = null;
|
||||||
return convertRes
|
return convertRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,16 +48,16 @@ class Convert {
|
||||||
*/
|
*/
|
||||||
_arrayToSchema() {
|
_arrayToSchema() {
|
||||||
// root节点基本信息
|
// 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) {
|
if (this._object.length > 0) {
|
||||||
// 创建items对象的基本信息
|
// 创建items对象的基本信息
|
||||||
let objectItem = this._object[0]
|
let objectItem = this._object[0]
|
||||||
result["items"] = this._value2object(objectItem, `#/items`, 'items')
|
result["items"] = this._value2object(objectItem, `#/items`, 'items');
|
||||||
if (isObject(objectItem) && !isEmpty(objectItem)) {
|
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
|
return result
|
||||||
|
@ -90,9 +90,9 @@ class Convert {
|
||||||
let result = {};
|
let result = {};
|
||||||
// 判断传入object是对象还是数组。
|
// 判断传入object是对象还是数组。
|
||||||
if (isArray(object)) {
|
if (isArray(object)) {
|
||||||
result.items = {}
|
result.items = {};
|
||||||
} else {
|
} else {
|
||||||
result.properties = {}
|
result.properties = {};
|
||||||
}
|
}
|
||||||
// 遍历传入的对象
|
// 遍历传入的对象
|
||||||
for (const key in object) {
|
for (const key in object) {
|
||||||
|
@ -100,7 +100,7 @@ class Convert {
|
||||||
const element = object[key];
|
const element = object[key];
|
||||||
// 如果只是undefined。跳过
|
// 如果只是undefined。跳过
|
||||||
if (element === undefined) {
|
if (element === undefined) {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
let $id = `${name}/properties/${key}`
|
let $id = `${name}/properties/${key}`
|
||||||
// 判断当前 element 的值 是否也是对象,如果是就继续递归,不是就赋值给result
|
// 判断当前 element 的值 是否也是对象,如果是就继续递归,不是就赋值给result
|
||||||
|
@ -111,22 +111,22 @@ class Convert {
|
||||||
// 针对空数组和有值的数组做不同处理
|
// 针对空数组和有值的数组做不同处理
|
||||||
if (element.length > 0) {
|
if (element.length > 0) {
|
||||||
// 如果是数组,那么就取第一项
|
// 如果是数组,那么就取第一项
|
||||||
let elementItem = element[0]
|
let elementItem = element[0];
|
||||||
// 创建items对象的基本信息
|
// 创建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)) {
|
if (isObject(elementItem) && !isEmpty(elementItem)) {
|
||||||
// 新增的properties才合并进来
|
// 新增的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 {
|
} 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 {
|
} else {
|
||||||
// 一般属性直接获取基本信息
|
// 一般属性直接获取基本信息
|
||||||
result["properties"][key] = this._value2object(element, $id, key)
|
result["properties"][key] = this._value2object(element, $id, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,29 +150,31 @@ class Convert {
|
||||||
|
|
||||||
// 判断是否为初始化root数据
|
// 判断是否为初始化root数据
|
||||||
if (root) {
|
if (root) {
|
||||||
objectTemplate["$schema"] = this._option.$schema
|
objectTemplate["$schema"] = this._option.$schema;
|
||||||
objectTemplate["title"] = `The Root Schema`
|
objectTemplate["title"] = `The Root Schema`;
|
||||||
objectTemplate["mock"] = undefined
|
objectTemplate["mock"] = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInteger(value)) {
|
if (isInteger(value)) {
|
||||||
objectTemplate.type = "integer"
|
objectTemplate.type = "integer";
|
||||||
} else if (isNumber(value)) {
|
} else if (isNumber(value)) {
|
||||||
objectTemplate.type = "number"
|
objectTemplate.type = "number";
|
||||||
} else if (isString(value)) {
|
} else if (isString(value)) {
|
||||||
objectTemplate.type = "string"
|
objectTemplate.type = "string";
|
||||||
} else if (isBoolean(value)) {
|
} else if (isBoolean(value)) {
|
||||||
objectTemplate.type = "boolean"
|
objectTemplate.type = "boolean";
|
||||||
} else if (isNull(value)) {
|
} else if (isNull(value)) {
|
||||||
objectTemplate.type = "null"
|
objectTemplate.type = "null";
|
||||||
} else if (isArray(value)) {
|
} else if (isArray(value)) {
|
||||||
objectTemplate.type = "array"
|
objectTemplate.type = "array";
|
||||||
|
objectTemplate["mock"] = undefined;
|
||||||
} else if (isObject(value)) {
|
} else if (isObject(value)) {
|
||||||
objectTemplate.type = "object"
|
objectTemplate.type = "object"
|
||||||
|
objectTemplate["mock"] = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return objectTemplate
|
return objectTemplate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Convert
|
module.exports = Convert;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit e50f0463826ac4d7837ea3a237333827774a1b19
|
Subproject commit e7709b9a340394e78610b91105b2cec0f1b8289d
|
Loading…
Reference in New Issue