refactor(接口测试): TCP请求的请求体改为json,xml,raw格式;场景增加批量创建性能测试按钮
TCP请求的请求体改为json,xml,raw格式;场景增加批量创建性能测试按钮
This commit is contained in:
parent
c79c753654
commit
929d3ae465
|
@ -298,9 +298,7 @@ public class APITestController {
|
|||
|
||||
long taskCountInThisWeek = scheduleService.countTaskByProjectIdInThisWeek(projectId);
|
||||
apiCountResult.setThisWeekAddedCount(taskCountInThisWeek);
|
||||
// long api_executedInThisWeekCountNumber = apiReportService.countByProjectIdAndCreateInThisWeek(projectId);
|
||||
long executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIdAndCreateAndByScheduleInThisWeek(projectId);
|
||||
// long executedInThisWeekCountNumber = api_executedInThisWeekCountNumber+scene_executedInThisWeekCountNumber;
|
||||
apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber);
|
||||
|
||||
//统计 失败 成功 以及总数
|
||||
|
|
|
@ -242,6 +242,11 @@ public class ApiAutomationController {
|
|||
return apiAutomationService.genPerformanceTestJmx(runRequest);
|
||||
}
|
||||
|
||||
@PostMapping("/batchGenPerformanceTestJmx")
|
||||
public List<JmxInfoDTO> batchGenPerformanceTestJmx(@RequestBody ApiScenarioBatchRequest request) {
|
||||
return apiAutomationService.batchGenPerformanceTestJmx(request);
|
||||
}
|
||||
|
||||
@PostMapping("/file/download")
|
||||
public ResponseEntity<byte[]> download(@RequestBody FileOperationRequest fileOperationRequest) {
|
||||
byte[] bytes = apiAutomationService.loadFileAsBytes(fileOperationRequest);
|
||||
|
|
|
@ -13,9 +13,15 @@ import java.util.Map;
|
|||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
public class JmxInfoDTO {
|
||||
private String name;
|
||||
private String xml;
|
||||
private String id;
|
||||
private Map<String, String> attachFiles;
|
||||
|
||||
public JmxInfoDTO(String name,String xml,Map<String, String> attachFiles){
|
||||
this.name = name;
|
||||
this.xml = xml;
|
||||
this.attachFiles = attachFiles;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
package io.metersphere.api.dto.automation;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* //ESB数据格式
|
||||
*
|
||||
* @author song.tianyang
|
||||
* @Date 2021/3/15 4:37 下午
|
||||
* @Description
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class TcpTreeTableDataStruct {
|
||||
private String uuid;
|
||||
private String name;
|
||||
private String value;
|
||||
private String type;
|
||||
private String systemName;
|
||||
private String contentType;
|
||||
private boolean required;
|
||||
private String description;
|
||||
private List<TcpTreeTableDataStruct> children;
|
||||
private String status = "";
|
||||
|
||||
public void init(){
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
this.systemName = "";
|
||||
this.description = "";
|
||||
this.value="";
|
||||
this.required = true;
|
||||
this.contentType = "";
|
||||
this.type = "";
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean initDefaultData(String name, String typeLength,String chineseName,String desc){
|
||||
this.init();
|
||||
if(StringUtils.isEmpty(name)){return false; }
|
||||
if(typeLength == null){
|
||||
typeLength = "";
|
||||
}else{
|
||||
typeLength = typeLength.trim();
|
||||
typeLength = typeLength.toLowerCase();
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
|
||||
if(typeLength.startsWith("string")){
|
||||
this.type = "string";
|
||||
String lengthStr = typeLength.substring(6);
|
||||
if(lengthStr.startsWith("(") && lengthStr.endsWith(")")){
|
||||
try {
|
||||
int length = Integer.parseInt(lengthStr.substring(1,lengthStr.length()-1));
|
||||
this.contentType = String.valueOf(length);
|
||||
}catch (Exception e){ }
|
||||
|
||||
}
|
||||
}else if(typeLength.startsWith("array")){
|
||||
this.type = "array";
|
||||
}else{
|
||||
this.type = "object";
|
||||
}
|
||||
|
||||
if(StringUtils.isEmpty(desc)){desc = "";}
|
||||
if(StringUtils.isNotEmpty(chineseName)){
|
||||
this.description = chineseName+":"+desc;
|
||||
}else{
|
||||
this.description =desc;
|
||||
}
|
||||
|
||||
if(this.description.endsWith(":")){
|
||||
this.description = this.description.substring(0,this.description.length()-1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public TcpTreeTableDataStruct copy(boolean copyChildren) {
|
||||
TcpTreeTableDataStruct returnObj = new TcpTreeTableDataStruct();
|
||||
returnObj.name = this.name;
|
||||
returnObj.value = this.value;
|
||||
returnObj.type = this.type;
|
||||
returnObj.systemName = this.systemName;
|
||||
returnObj.contentType = this.contentType;
|
||||
returnObj.required = this.required;
|
||||
returnObj.description = this.description;
|
||||
if (copyChildren) {
|
||||
returnObj.children = this.children;
|
||||
} else {
|
||||
returnObj.children = new ArrayList<>();
|
||||
}
|
||||
return returnObj;
|
||||
}
|
||||
|
||||
public Element genXmlElementByChildren(Element document) {
|
||||
this.name = this.name.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
.replace("\"", """).replace("©", "'");
|
||||
if (StringUtils.isEmpty(this.name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Element element = null;
|
||||
try {
|
||||
element = document.addElement(this.name);
|
||||
if (StringUtils.equalsAnyIgnoreCase(type, "string", "array")) {
|
||||
long lengthNum = Long.parseLong(this.contentType);
|
||||
String attrString = "";
|
||||
if (StringUtils.equalsIgnoreCase(this.type, "string")) {
|
||||
attrString = "s," + contentType;
|
||||
} else if (StringUtils.equalsIgnoreCase(this.type, "array")) {
|
||||
attrString = "a," + contentType;
|
||||
}
|
||||
element.addAttribute("attr", attrString);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println(this.name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
if (this.children == null || this.children.isEmpty()) {
|
||||
if(this.value == null ){
|
||||
this.value = "";
|
||||
}
|
||||
element.addText(this.value);
|
||||
} else {
|
||||
for (TcpTreeTableDataStruct child : children) {
|
||||
child.genXmlElementByChildren(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
public Element genXmlElementByDocument(Document document) {
|
||||
this.name = this.name.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
.replace("\"", """).replace("©", "'");
|
||||
if (StringUtils.isEmpty(this.name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Element element = null;
|
||||
try {
|
||||
element = document.addElement(this.name);
|
||||
if (StringUtils.equalsAnyIgnoreCase(type, "string", "array")) {
|
||||
long lengthNum = Long.parseLong(this.contentType);
|
||||
String attrString = "";
|
||||
if (StringUtils.equalsIgnoreCase(this.type, "string")) {
|
||||
attrString = "s," + contentType;
|
||||
} else if (StringUtils.equalsIgnoreCase(this.type, "array")) {
|
||||
attrString = "a," + contentType;
|
||||
}
|
||||
element.addAttribute("attr", attrString);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println(this.name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
if (this.children == null || this.children.isEmpty()) {
|
||||
element.addText(this.value);
|
||||
} else {
|
||||
for (TcpTreeTableDataStruct child : children) {
|
||||
child.genXmlElementByChildren(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package io.metersphere.api.dto.automation.parse;
|
||||
|
||||
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author song.tianyang
|
||||
* @Date 2021/3/15 5:00 下午
|
||||
* @Description
|
||||
*/
|
||||
public class TcpTreeTableDataParser {
|
||||
public static String treeTableData2Xml(List<TcpTreeTableDataStruct> treeDataList) {
|
||||
String xmlString = "";
|
||||
try {
|
||||
if (treeDataList == null || treeDataList.isEmpty()) {
|
||||
return xmlString;
|
||||
}
|
||||
// 创建解析器工厂
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder db = factory.newDocumentBuilder();
|
||||
Document document = DocumentHelper.createDocument();
|
||||
|
||||
TcpTreeTableDataStruct dataStruct = null;
|
||||
if(treeDataList.size()>1){
|
||||
dataStruct = new TcpTreeTableDataStruct();
|
||||
dataStruct.setName("ROOT");
|
||||
dataStruct.setChildren(treeDataList);
|
||||
}else {
|
||||
dataStruct = treeDataList.get(0);
|
||||
}
|
||||
|
||||
dataStruct.genXmlElementByDocument(document);
|
||||
xmlString = document.getRootElement().asXML();
|
||||
|
||||
// 设置XML文档格式
|
||||
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
|
||||
// 设置XML编码方式,即是用指定的编码方式保存XML文档到字符串(String),这里也可以指定为GBK或是ISO8859-1
|
||||
outputFormat.setEncoding("UTF-8");
|
||||
//outputFormat.setSuppressDeclaration(true); //是否生产xml头
|
||||
outputFormat.setIndent(true); //设置是否缩进
|
||||
outputFormat.setNewlines(true); //设置是否换行
|
||||
|
||||
try {
|
||||
// stringWriter字符串是用来保存XML文档的
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
// xmlWriter是用来把XML文档写入字符串的(工具)
|
||||
XMLWriter xmlWriter = new XMLWriter(stringWriter, outputFormat);
|
||||
// 把创建好的XML文档写入字符串
|
||||
xmlWriter.write(document);
|
||||
|
||||
// 打印字符串,即是XML文档
|
||||
xmlString = stringWriter.toString();
|
||||
xmlWriter.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (StringUtils.isEmpty(xmlString)) {
|
||||
xmlString = "";
|
||||
} else {
|
||||
xmlString = xmlString.replaceAll(" ", "");
|
||||
}
|
||||
return xmlString;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
|||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.metersphere.api.dto.automation.EsbDataStruct;
|
||||
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
|
||||
|
@ -88,6 +89,14 @@ public class MsTCPSampler extends MsTestElement {
|
|||
private String projectId;
|
||||
@JSONField(ordinal = 40)
|
||||
private String connectEncoding;
|
||||
@JSONField(ordinal = 41)
|
||||
private String reportType;
|
||||
@JSONField(ordinal = 42)
|
||||
private List<TcpTreeTableDataStruct> xmlDataStruct;
|
||||
@JSONField(ordinal = 43)
|
||||
private String jsonDataStruct;
|
||||
@JSONField(ordinal = 44)
|
||||
private String rawDataStruct;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -466,7 +466,6 @@ public class APITestService {
|
|||
/**
|
||||
* 更新jmx数据,处理jmx里的各种参数
|
||||
* <p>
|
||||
* 注: 与1.7分支合并时,如果该方法产生冲突,请以master为准
|
||||
*
|
||||
* @param jmxString 原JMX文件
|
||||
* @param testNameParam 某些节点要替换的testName
|
||||
|
@ -475,7 +474,6 @@ public class APITestService {
|
|||
* @author song tianyang
|
||||
*/
|
||||
public JmxInfoDTO updateJmxString(String jmxString, String testNameParam, boolean isFromScenario) {
|
||||
//注: 与1.7分支合并时,如果该方法产生冲突,请以master为准
|
||||
String attribute_testName = "testname";
|
||||
String[] requestElementNameArr = new String[]{"HTTPSamplerProxy", "TCPSampler", "JDBCSampler", "DubboSample"};
|
||||
|
||||
|
|
|
@ -125,6 +125,8 @@ public class ApiAutomationService {
|
|||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private TestPlanMapper testPlanMapper;
|
||||
@Resource
|
||||
private TcpApiParamService tcpApiParamService;
|
||||
|
||||
public ApiScenarioWithBLOBs getDto(String id) {
|
||||
return apiScenarioMapper.selectByPrimaryKey(id);
|
||||
|
@ -320,6 +322,8 @@ public class ApiAutomationService {
|
|||
|
||||
//检查场景的请求步骤。如果含有ESB请求步骤的话,要做参数计算处理。
|
||||
esbApiParamService.checkScenarioRequests(request);
|
||||
//如果场景有TCP步骤的话,也要做参数计算处理
|
||||
tcpApiParamService.checkTestElement(request.getScenarioDefinition());
|
||||
|
||||
final ApiScenarioWithBLOBs scenario = buildSaveScenario(request);
|
||||
|
||||
|
@ -1346,21 +1350,9 @@ public class ApiAutomationService {
|
|||
return request.getId();
|
||||
}
|
||||
|
||||
private void preduceTestElement(RunDefinitionRequest request) throws Exception {
|
||||
public void preduceTestElement(RunDefinitionRequest request) throws Exception {
|
||||
if (request.getTestElement() != null) {
|
||||
for (MsTestElement threadGroup : request.getTestElement().getHashTree()) {
|
||||
if (threadGroup instanceof MsThreadGroup && threadGroup.getHashTree() != null) {
|
||||
for (MsTestElement scenario : threadGroup.getHashTree()) {
|
||||
if (scenario instanceof MsScenario && scenario.getHashTree() != null) {
|
||||
for (MsTestElement itemElement : scenario.getHashTree()) {
|
||||
if (itemElement instanceof MsScenario) {
|
||||
itemElement.setId(UUID.randomUUID().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tcpApiParamService.checkTestElement(request.getTestElement());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1548,8 +1540,10 @@ public class ApiAutomationService {
|
|||
List<String> ids = request.getIds();
|
||||
apiScenarios = extApiScenarioMapper.selectIds(ids);
|
||||
String testName = "";
|
||||
String id = "";
|
||||
if (!apiScenarios.isEmpty()) {
|
||||
testName = apiScenarios.get(0).getName();
|
||||
id = apiScenarios.get(0).getId();
|
||||
}
|
||||
if (CollectionUtils.isEmpty(apiScenarios)) {
|
||||
return null;
|
||||
|
@ -1560,6 +1554,7 @@ public class ApiAutomationService {
|
|||
|
||||
String name = request.getName() + ".jmx";
|
||||
dto.setName(name);
|
||||
dto.setId(id);
|
||||
return dto;
|
||||
}
|
||||
|
||||
|
@ -2117,4 +2112,28 @@ public class ApiAutomationService {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
public List<JmxInfoDTO> batchGenPerformanceTestJmx(ApiScenarioBatchRequest request) {
|
||||
ServiceUtils.getSelectAllIds(request, request.getCondition(),
|
||||
(query) -> extApiScenarioMapper.selectIdsByQuery((ApiScenarioRequest) query));
|
||||
List<JmxInfoDTO> returnList = new ArrayList<>();
|
||||
|
||||
List<String> ids = request.getIds();
|
||||
List<ApiScenarioWithBLOBs> apiScenarioList = extApiScenarioMapper.selectIds(ids);
|
||||
if (CollectionUtils.isEmpty(apiScenarioList)) {
|
||||
return returnList;
|
||||
}else {
|
||||
apiScenarioList.forEach(item ->{
|
||||
String testName = item.getName();
|
||||
MsTestPlan testPlan = new MsTestPlan();
|
||||
testPlan.setHashTree(new LinkedList<>());
|
||||
JmxInfoDTO dto = apiTestService.updateJmxString(generateJmx(item), testName, true);
|
||||
String name = item.getName() + ".jmx";
|
||||
dto.setId(item.getId());
|
||||
dto.setName(name);
|
||||
returnList.add(dto);
|
||||
});
|
||||
return returnList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,6 +100,8 @@ public class ApiDefinitionService {
|
|||
@Resource
|
||||
private EsbApiParamService esbApiParamService;
|
||||
@Resource
|
||||
private TcpApiParamService tcpApiParamService;
|
||||
@Resource
|
||||
private ApiModuleMapper apiModuleMapper;
|
||||
@Resource
|
||||
private SystemParameterService systemParameterService;
|
||||
|
@ -277,6 +279,8 @@ public class ApiDefinitionService {
|
|||
if (StringUtils.equals(request.getMethod(), "ESB")) {
|
||||
//ESB的接口类型数据,采用TCP方式去发送。并将方法类型改为TCP。 并修改发送数据
|
||||
request = esbApiParamService.handleEsbRequest(request);
|
||||
}else if(StringUtils.equals(request.getMethod(), "TCP")) {
|
||||
request = tcpApiParamService.handleTcpRequest(request);
|
||||
}
|
||||
final ApiDefinitionWithBLOBs test = new ApiDefinitionWithBLOBs();
|
||||
test.setId(request.getId());
|
||||
|
@ -581,6 +585,13 @@ public class ApiDefinitionService {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
try{
|
||||
//检查TCP数据结构,等其他进行处理
|
||||
tcpApiParamService.checkTestElement(request.getTestElement());
|
||||
}catch (Exception e){
|
||||
}
|
||||
|
||||
HashTree hashTree = request.getTestElement().generateHashTree(config);
|
||||
String runMode = ApiRunMode.DEFINITION.name();
|
||||
if (StringUtils.isNotBlank(request.getType()) && StringUtils.equals(request.getType(), ApiRunMode.API_PLAN.name())) {
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package io.metersphere.api.service;
|
||||
|
||||
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
|
||||
import io.metersphere.api.dto.automation.parse.TcpTreeTableDataParser;
|
||||
import io.metersphere.api.dto.definition.*;
|
||||
import io.metersphere.api.dto.definition.request.MsScenario;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author song.tianyang
|
||||
* @Date 2021/3/16 4:57 下午
|
||||
* @Description
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class TcpApiParamService {
|
||||
|
||||
public SaveApiDefinitionRequest handleTcpRequest(SaveApiDefinitionRequest request) {
|
||||
MsTCPSampler tcpSampler = this.handleTcpRequest(request.getRequest());
|
||||
if(tcpSampler != null){
|
||||
request.setRequest(tcpSampler);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
public MsTCPSampler handleTcpRequest(MsTestElement testElement){
|
||||
MsTCPSampler tcpSampler = null;
|
||||
try {
|
||||
if(testElement instanceof MsTCPSampler){
|
||||
tcpSampler = (MsTCPSampler)testElement;
|
||||
String reportType = tcpSampler.getReportType();
|
||||
if (StringUtils.isNotEmpty(reportType)) {
|
||||
switch (reportType) {
|
||||
case "raw":
|
||||
tcpSampler.setRequest(tcpSampler.getRawDataStruct());
|
||||
break;
|
||||
case "xml":
|
||||
String xmlDataStruct = this.genValueFromEsbDataStructByParam(tcpSampler.getXmlDataStruct());
|
||||
tcpSampler.setRequest(xmlDataStruct);
|
||||
break;
|
||||
case "json":
|
||||
tcpSampler.setRequest(tcpSampler.getJsonDataStruct());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return tcpSampler;
|
||||
}
|
||||
|
||||
//通过报文模版中的变量参数,解析报文数据结构,生成对应的xml数据
|
||||
private String genValueFromEsbDataStructByParam(List<TcpTreeTableDataStruct> dataStructRequestList) {
|
||||
String returnValue = TcpTreeTableDataParser.treeTableData2Xml(dataStructRequestList);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public void checkTestElement(MsTestElement testElement) {
|
||||
if(testElement != null){
|
||||
if(testElement instanceof MsTCPSampler){
|
||||
this.handleTcpRequest(testElement);
|
||||
}else if (testElement instanceof MsScenario) {
|
||||
testElement.setId(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
if(testElement.getHashTree() != null){
|
||||
for (MsTestElement itemElement : testElement.getHashTree()) {
|
||||
this.checkTestElement(itemElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -709,6 +709,11 @@
|
|||
"name": "创建性能测试",
|
||||
"resourceId": "PROJECT_API_SCENARIO"
|
||||
},
|
||||
{
|
||||
"id": "PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH",
|
||||
"name": "批量创建性能测试",
|
||||
"resourceId": "PROJECT_API_SCENARIO"
|
||||
},
|
||||
{
|
||||
"id": "PROJECT_API_REPORT:READ",
|
||||
"name": "查询报告",
|
||||
|
|
|
@ -368,6 +368,11 @@ export default {
|
|||
handleClick: this.handleBatchEdit,
|
||||
permissions: ['PROJECT_API_SCENARIO:READ+EDIT']
|
||||
},
|
||||
{
|
||||
name: this.$t('api_test.create_performance_test_batch'),
|
||||
handleClick: this.batchCreatePerformance,
|
||||
permissions: ['PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH']
|
||||
},
|
||||
{
|
||||
name: this.$t('test_track.case.batch_move_case'),
|
||||
handleClick: this.handleBatchMove,
|
||||
|
@ -821,7 +826,39 @@ export default {
|
|||
},
|
||||
callBackSelect(selection){
|
||||
this.$emit('selection', selection);
|
||||
}
|
||||
},
|
||||
batchCreatePerformance() {
|
||||
this.$alert(this.$t('api_test.definition.request.batch_to_performance_confirm') + " ?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
this.infoDb = false;
|
||||
let param = {};
|
||||
this.buildBatchParam(param);
|
||||
this.$post('/api/automation/batchGenPerformanceTestJmx/', param, response => {
|
||||
let returnDataList = response.data;
|
||||
let jmxObjList = [];
|
||||
returnDataList.forEach(item => {
|
||||
let jmxObj = {};
|
||||
jmxObj.name = item.name;
|
||||
jmxObj.xml = item.xml;
|
||||
jmxObj.attachFiles = item.attachFiles;
|
||||
jmxObj.attachByteFiles = item.attachByteFiles;
|
||||
jmxObj.scenarioId = item.id;
|
||||
jmxObjList.push(jmxObj);
|
||||
});
|
||||
this.$store.commit('setScenarioJmxs', {
|
||||
name: 'Scenarios',
|
||||
jmxs: jmxObjList
|
||||
});
|
||||
this.$router.push({
|
||||
path: "/performance/test/create"
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -44,10 +44,13 @@
|
|||
:showScript="false"
|
||||
:is-read-only="this.isCompReadOnly"
|
||||
ref="esbDefinition"/>
|
||||
<ms-tcp-basis-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "
|
||||
:request="request"
|
||||
:is-read-only="isCompReadOnly"
|
||||
:showScript="false"/>
|
||||
<!-- <ms-tcp-basis-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "-->
|
||||
<!-- :request="request"-->
|
||||
<!-- :is-read-only="isCompReadOnly"-->
|
||||
<!-- :showScript="false"/>-->
|
||||
<ms-tcp-format-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "
|
||||
:is-read-only="isCompReadOnly"
|
||||
:show-script="false" :request="request"/>
|
||||
<ms-sql-basis-parameters v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'"
|
||||
:request="request"
|
||||
:is-read-only="isCompReadOnly"
|
||||
|
@ -91,7 +94,8 @@
|
|||
|
||||
<script>
|
||||
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
|
||||
import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
|
||||
// import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
|
||||
import MsTcpFormatParameters from "../../../definition/components/request/tcp/TcpFormatParameters";
|
||||
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
|
||||
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
|
||||
import MsRequestResultTail from "../../../definition/components/response/RequestResultTail";
|
||||
|
@ -131,7 +135,7 @@ export default {
|
|||
components: {
|
||||
CustomizeReqInfo,
|
||||
ApiBaseComponent, ApiResponseComponent,
|
||||
MsSqlBasisParameters, MsTcpBasisParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun,
|
||||
MsSqlBasisParameters, MsTcpFormatParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun,
|
||||
"esbDefinition": esbDefinition.default,
|
||||
"esbDefinitionResponse": esbDefinitionResponse.default
|
||||
},
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
<!-- 请求参数 -->
|
||||
<div v-if="apiProtocol=='TCP'">
|
||||
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
|
||||
<ms-basis-parameters :show-script="false" :request="request"/>
|
||||
<!-- <ms-basis-parameters :show-script="false" :request="request"/>-->
|
||||
<ms-tcp-format-parameters :show-script="false" :request="request"/>
|
||||
</div>
|
||||
<div v-else-if="apiProtocol=='ESB'">
|
||||
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
|
||||
|
@ -43,7 +44,7 @@
|
|||
|
||||
<script>
|
||||
import MsTcpBasicApi from "./TCPBasicApi";
|
||||
import MsBasisParameters from "../request/tcp/TcpBasisParameters";
|
||||
import MsTcpFormatParameters from "../request/tcp/TcpFormatParameters";
|
||||
import MsChangeHistory from "../../../../history/ChangeHistory";
|
||||
import {hasLicense} from "@/common/js/utils";
|
||||
|
||||
|
@ -52,7 +53,7 @@ const esbDefinition = (requireComponent!=null&&requireComponent.keys().length) >
|
|||
const esbDefinitionResponse = (requireComponent!=null&&requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinitionResponse.vue") : {};
|
||||
export default {
|
||||
name: "MsAddCompleteTcpApi",
|
||||
components: {MsTcpBasicApi, MsBasisParameters,MsChangeHistory,
|
||||
components: {MsTcpBasicApi, MsTcpFormatParameters,MsChangeHistory,
|
||||
"esbDefinition": esbDefinition.default,
|
||||
"esbDefinitionResponse": esbDefinitionResponse.default},
|
||||
props: {
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
<template>
|
||||
<div class="ms-border">
|
||||
<el-table
|
||||
:data="tableData" @cell-dblclick="editRow"
|
||||
row-key="uuid" :expand-row-keys="tableExpandRowKayArray"
|
||||
default-expand-all
|
||||
v-loading="loading"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
|
||||
|
||||
<el-table-column prop="name" :label="$t('api_test.definition.request.esb_table.name')" width="230">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.status" v-model="scope.row.name" style="width: 140px"></el-input>
|
||||
<span v-else>{{scope.row.name}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="type" :label="$t('api_test.definition.request.esb_table.type')" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-if="scope.row.status" v-model="scope.row.type" :placeholder="$t('commons.please_select')">
|
||||
<el-option v-for="item in typeSelectOptions " :key="item.value" :label="item.value" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<span v-else>{{scope.row.type}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="length" :label="$t('api_test.definition.request.esb_table.length')" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.status" v-model="scope.row.contentType"></el-input>
|
||||
<span v-else>{{scope.row.contentType}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="description" :label="$t('api_test.definition.request.esb_table.desc')" min-width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.status" v-model="scope.row.description"></el-input>
|
||||
<span v-else>{{scope.row.description}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="value" :label="$t('api_test.definition.request.esb_table.value')" width="180">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.status" v-model="scope.row.value"></el-input>
|
||||
<span v-else>{{scope.row.value}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="showOptionsButton" :label="$t('commons.operating')" width="140" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<span>
|
||||
<el-button size="mini" p="$t('commons.next_level')" icon="el-icon-plus" type="primary" circle @click="nextRow(scope.row)"
|
||||
class="ht-btn-confirm"/>
|
||||
<el-button size="mini" p="$t('commons.copy')" icon="el-icon-copy-document" type="primary" circle @click="copyDataStructConfirm(scope.row)"
|
||||
class="ht-btn-confirm"/>
|
||||
<el-button size="mini" p="$t('commons.remove')" icon="el-icon-close" circle @click="remove(scope.row)"
|
||||
class="ht-btn-remove"/>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="showOptionsButton">
|
||||
<el-button class="ht-btn-add" size="mini" p="$t('commons.add')" icon="el-icon-circle-plus-outline" @click="add">{{$t("commons.add")}}</el-button>
|
||||
<el-button class="ht-btn-add" size="mini" p="$t('commons.add')" icon="el-icon-circle-plus-outline" @click="saveTableData">{{$t("commons.save")}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsTcpXmlTable",
|
||||
components: {},
|
||||
props: {
|
||||
tableData: Array,
|
||||
showOptionsButton:Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading:false,
|
||||
typeSelectOptions:[
|
||||
{ value: 'object', label: '[object]' },
|
||||
{ value: 'string', label: '[string]' },
|
||||
{ value: 'array', label: '[array]' },
|
||||
],
|
||||
requiredSelectOptions:[
|
||||
{ value: true, label: '必填' },
|
||||
{ value: false, label: '非必填' },
|
||||
],
|
||||
tableExpandRowKayArray:["name","systemName"],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if(this.tableData && this.tableData.length>0){
|
||||
this.tableData.forEach(row => {
|
||||
if(row.name == null || row.name === ""){
|
||||
this.remove(row);
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveTableData:function(){
|
||||
this.$emit('saveTableData',this.tableData);
|
||||
},
|
||||
remove: function (row) {
|
||||
this.removeTableRow(row);
|
||||
},
|
||||
add: function (r) {
|
||||
let row = this.getNewRow(null);
|
||||
this.pushTableData(row);
|
||||
},
|
||||
nextRow:function (row) {
|
||||
//首先保存当前行内容
|
||||
let confirmRowFlag = this.confirm(row);
|
||||
if(confirmRowFlag){
|
||||
let nextRow = this.getNewRow(null);
|
||||
this.pushTableData(nextRow,row.uuid);
|
||||
}
|
||||
},
|
||||
//复制当前数据结构
|
||||
copyDataStructConfirm:function (row){
|
||||
this.$alert(this.$t('api_test.definition.request.esb_copy_confirm') + " ?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
this.copyDataStruct(row);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
copyDataStruct:function (row){
|
||||
let parentRow = this.selectParentRow(this.tableData,row.uuid);
|
||||
let newRow = this.createNewId(row);
|
||||
if(parentRow!=null){
|
||||
if(parentRow.children == null){
|
||||
parentRow.children = [];
|
||||
}
|
||||
parentRow.children.push(newRow);
|
||||
}else{
|
||||
this.$emit('xmlTableDataPushRow',newRow);
|
||||
}
|
||||
},
|
||||
createNewId(row){
|
||||
let newRow = this.getNewRow(row);
|
||||
if(row.children!=null && row.children.length > 0){
|
||||
row.children.forEach(child => {
|
||||
let newChild = this.createNewId(child);
|
||||
newRow.children.push(newChild);
|
||||
});
|
||||
}
|
||||
return newRow;
|
||||
},
|
||||
selectParentRow(dataStruct,rowId){
|
||||
let returnRow = null;
|
||||
if(dataStruct == null || dataStruct.length === 0){
|
||||
return returnRow;
|
||||
}
|
||||
dataStruct.forEach( itemData => {
|
||||
if(itemData.children != null && itemData.children.length > 0){
|
||||
itemData.children.forEach( child => {
|
||||
if(child.uuid === rowId){
|
||||
returnRow = itemData;
|
||||
return returnRow;
|
||||
}
|
||||
});
|
||||
}
|
||||
if(returnRow == null ){
|
||||
if(itemData.children != null && itemData.children.length > 0){
|
||||
returnRow = this.selectParentRow(itemData.children,rowId);
|
||||
if(returnRow!=null){
|
||||
return returnRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return returnRow;
|
||||
},
|
||||
confirm: function (row) {
|
||||
this.validateRowData(row) ? row.status = '' : row.status;
|
||||
if (row.status === "") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getNewRow(param){
|
||||
if(param == null ){
|
||||
let row = {
|
||||
name: '',systemName: '',status: 'edit',type: '[object]',contentType: '',required: false,description: '',uuid: this.uuid(),children: []
|
||||
}
|
||||
return row;
|
||||
}else{
|
||||
let row = {
|
||||
name: param.name,
|
||||
systemName: param.systemName,
|
||||
status: '',
|
||||
type: param.type,
|
||||
contentType: param.contentType,
|
||||
required: param.required,
|
||||
description: param.description,
|
||||
uuid: this.uuid(),
|
||||
children: []
|
||||
}
|
||||
return row;
|
||||
}
|
||||
},
|
||||
validateRowData(row) {
|
||||
if(row.name == null || row.name === ''){
|
||||
// this.$warning(this.$t('load_test.input_ip'));
|
||||
this.$warning("参数名"+"不能为空,且不能包含英文小数点[.]");
|
||||
return false;
|
||||
}else if(row.name.indexOf(".")>0){
|
||||
this.$warning("参数名["+row.name+"]不合法,不能包含英文小数点\".\"!");
|
||||
return false;
|
||||
}else if(row.type == null || row.type === ''){
|
||||
this.$warning("类型"+"不能为空!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
editRow: function (row) {
|
||||
row.status = 'edit';
|
||||
},
|
||||
uuid: function () {
|
||||
return (((1 + Math.random()) * 0x100000) | 0).toString(16).substring(1);
|
||||
},
|
||||
pushTableData: function(dataRow,rowId){
|
||||
if(rowId === "" || rowId == null){
|
||||
if(this.tableData){
|
||||
this.$emit("initXmlTableData");
|
||||
}
|
||||
this.tableData.push(dataRow);
|
||||
}else {
|
||||
this.appendDataWithDeepForeach(this.tableData,rowId,dataRow);
|
||||
}
|
||||
},
|
||||
appendDataWithDeepForeach(datas,rowId,appendData){
|
||||
datas.forEach( row => {
|
||||
if(row.uuid === rowId){
|
||||
if(row.children == null){
|
||||
row.children = [];
|
||||
}
|
||||
row.children.push(appendData);
|
||||
}else if(row.children.length>0){
|
||||
let appendResult = this.appendDataWithDeepForeach(row.children,rowId,appendData);
|
||||
if(appendResult){
|
||||
return appendResult;
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
},
|
||||
removeTableRow: function (row){
|
||||
this.removeFromDataStruct(this.tableData,row);
|
||||
},
|
||||
removeFromDataStruct(dataStruct,row){
|
||||
if(dataStruct == null || dataStruct.length === 0){
|
||||
return;
|
||||
}
|
||||
let rowIndex = dataStruct.indexOf(row);
|
||||
if(rowIndex >= 0){
|
||||
dataStruct.splice(rowIndex,1);
|
||||
}else {
|
||||
dataStruct.forEach( itemData => {
|
||||
if(itemData.children != null && itemData.children.length > 0){
|
||||
this.removeFromDataStruct(itemData.children,row);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.ht-btn-remove {
|
||||
color: white;
|
||||
background-color: #DCDFE6;
|
||||
}
|
||||
|
||||
.ht-btn-confirm {
|
||||
color: white;
|
||||
/*background-color: #1483F6;*/
|
||||
}
|
||||
|
||||
.ht-btn-add {
|
||||
border: 0px;
|
||||
margin-top: 10px;
|
||||
color: #783887;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.ht-tb {
|
||||
background-color: white;
|
||||
border: 0px;
|
||||
}
|
||||
</style>
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
||||
<!-- TCP 请求参数 -->
|
||||
<tcp-basis-parameters :request="request" @callback="runDebug" ref="requestForm"/>
|
||||
|
||||
<!-- <tcp-basis-parameters :request="request" @callback="runDebug" ref="requestForm"/>-->
|
||||
<ms-tcp-format-parameters :request="request" @callback="runDebug" ref="requestForm"/>
|
||||
<!-- TCP 请求返回数据 -->
|
||||
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
|
||||
<ms-request-result-tail :response="responseData" :currentProtocol="currentProtocol" ref="debugResult"/>
|
||||
|
@ -58,7 +58,7 @@
|
|||
import {createComponent} from "../jmeter/components";
|
||||
import {REQ_METHOD} from "../../model/JsonData";
|
||||
import MsRequestResultTail from "../response/RequestResultTail";
|
||||
import TcpBasisParameters from "../request/tcp/TcpBasisParameters";
|
||||
import MsTcpFormatParameters from "@/business/components/api/definition/components/request/tcp/TcpFormatParameters";
|
||||
import MsJmxStep from "../step/JmxStep";
|
||||
import MsApiCaseList from "../case/ApiCaseList";
|
||||
|
||||
|
@ -66,7 +66,7 @@
|
|||
name: "ApiConfig",
|
||||
components: {
|
||||
MsJmxStep,
|
||||
TcpBasisParameters,
|
||||
MsTcpFormatParameters,
|
||||
MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun, MsApiCaseList
|
||||
},
|
||||
props: {
|
||||
|
|
|
@ -0,0 +1,497 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="21" style="padding-bottom: 20px">
|
||||
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin: 10px">
|
||||
<el-form class="tcp" :model="request" :rules="rules" ref="request" :disabled="isReadOnly" style="margin: 20px">
|
||||
<el-tabs v-model="activeName" class="request-tabs">
|
||||
<!--query 参数-->
|
||||
<el-tab-pane :label="$t('api_test.definition.document.request_body')" name="request">
|
||||
<el-radio-group v-model="reportType" size="mini" style="margin: 10px 0px;">
|
||||
<el-radio :disabled="isReadOnly" label="json" @change="changeReportType">
|
||||
json
|
||||
</el-radio>
|
||||
<el-radio :disabled="isReadOnly" label="xml" @change="changeReportType">
|
||||
xml
|
||||
</el-radio>
|
||||
<el-radio :disabled="isReadOnly" label="raw" @change="changeReportType">
|
||||
raw
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<div style="min-width: 1200px;" v-if="request.reportType === 'xml'">
|
||||
<tcp-xml-table :table-data="request.xmlDataStruct" :show-options-button="true"
|
||||
@initXmlTableData="initXmlTableData"
|
||||
@saveTableData="saveXmlTableData" ref="treeTable"></tcp-xml-table>
|
||||
</div>
|
||||
<div style="min-width: 1200px;" v-if="request.reportType === 'json'">
|
||||
<div class="send-request">
|
||||
<ms-code-edit mode="json" :read-only="isReadOnly" :data.sync="request.jsonDataStruct" :modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
|
||||
</div>
|
||||
</div>
|
||||
<div style="min-width: 1200px;" v-if="request.reportType === 'raw'">
|
||||
<div class="send-request">
|
||||
<ms-code-edit mode="text" :read-only="isReadOnly" :data.sync="request.rawDataStruct" :modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('api_test.definition.request.pre_script')" name="script">
|
||||
<jsr233-processor-content
|
||||
:jsr223-processor="request.tcpPreProcessor"
|
||||
:is-pre-processor="true"
|
||||
:is-read-only="isReadOnly"/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('api_test.definition.request.other_config')" name="other" class="other-config">
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="TCPClient" prop="classname">
|
||||
<el-select v-model="request.classname" style="width: 100%" size="small">
|
||||
<el-option v-for="c in classes" :key="c" :label="c" :value="c"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="$t('api_test.request.tcp.connect')" prop="ctimeout">
|
||||
<el-input-number v-model="request.ctimeout" controls-position="right" :min="0" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="$t('api_test.request.tcp.response')" prop="timeout">
|
||||
<el-input-number v-model="request.timeout" controls-position="right" :min="0" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="6">
|
||||
<el-form-item :label="$t('api_test.request.tcp.so_linger')" prop="soLinger">
|
||||
<el-input v-model="request.soLinger" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6">
|
||||
<el-form-item :label="$t('api_test.request.tcp.eol_byte')" prop="eolByte">
|
||||
<el-input v-model="request.eolByte" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6">
|
||||
<el-form-item :label="$t('api_test.request.tcp.username')" prop="username">
|
||||
<el-input v-model="request.username" maxlength="100" show-word-limit size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item :label="$t('api_test.request.tcp.password')" prop="password">
|
||||
<el-input v-model="request.password" maxlength="30" show-word-limit show-password
|
||||
autocomplete="new-password" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="10" style="margin-left: 30px">
|
||||
<el-col :span="6">
|
||||
<el-form-item :label="$t('api_test.request.tcp.re_use_connection')">
|
||||
<el-checkbox v-model="request.reUseConnection"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item :label="$t('api_test.request.tcp.close_connection')">
|
||||
<el-checkbox v-model="request.closeConnection"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item :label="$t('api_test.request.tcp.no_delay')">
|
||||
<el-checkbox v-model="request.nodelay"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="Connect encoding">
|
||||
<el-select v-model="request.connectEncoding" style="width: 100px" size="small">
|
||||
<el-option v-for="item in connectEncodingArr" :key="item.key" :label="item.value" :value="item.key"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
</el-col>
|
||||
|
||||
<!--操作按钮-->
|
||||
<api-definition-step-button :request="request" v-if="!referenced && showScript"/>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsApiKeyValue from "../../ApiKeyValue";
|
||||
import MsApiAssertions from "../../assertion/ApiAssertions";
|
||||
import MsApiExtract from "../../extract/ApiExtract";
|
||||
import ApiRequestMethodSelect from "../../collapse/ApiRequestMethodSelect";
|
||||
import MsCodeEdit from "../../../../../common/components/MsCodeEdit";
|
||||
import MsApiScenarioVariables from "../../ApiScenarioVariables";
|
||||
import {createComponent} from "../../jmeter/components";
|
||||
import {Assertions, Extract} from "../../../model/ApiTestModel";
|
||||
import {parseEnvironment} from "../../../model/EnvironmentModel";
|
||||
import ApiEnvironmentConfig from "../../environment/ApiEnvironmentConfig";
|
||||
import {API_STATUS} from "../../../model/JsonData";
|
||||
import TCPSampler from "../../jmeter/components/sampler/tcp-sampler";
|
||||
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
|
||||
import MsApiVariable from "../../ApiVariable";
|
||||
import MsInstructionsIcon from "../../../../../common/components/MsInstructionsIcon";
|
||||
import Jsr233ProcessorContent from "../../../../automation/scenario/common/Jsr233ProcessorContent";
|
||||
import JSR223PreProcessor from "../../jmeter/components/pre-processors/jsr223-pre-processor";
|
||||
import ApiDefinitionStepButton from "../components/ApiDefinitionStepButton";
|
||||
import TcpXmlTable from "@/business/components/api/definition/components/complete/table/TcpXmlTable";
|
||||
|
||||
|
||||
export default {
|
||||
name: "MsTcpFormatParameters",
|
||||
components: {
|
||||
TcpXmlTable,
|
||||
ApiDefinitionStepButton,
|
||||
Jsr233ProcessorContent,
|
||||
MsInstructionsIcon,
|
||||
MsApiVariable,
|
||||
MsApiScenarioVariables,
|
||||
MsCodeEdit,
|
||||
ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiKeyValue, ApiEnvironmentConfig
|
||||
},
|
||||
props: {
|
||||
request: {},
|
||||
basisData: {},
|
||||
moduleOptions: Array,
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showScript: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
referenced: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: "request",
|
||||
classes: TCPSampler.CLASSES,
|
||||
reportType:"xml",
|
||||
isReloadData: false,
|
||||
refreshedXmlTable:true,
|
||||
options: API_STATUS,
|
||||
currentProjectId: "",
|
||||
connectEncodingArr:[
|
||||
{
|
||||
'key':'UTF-8',
|
||||
'value':'UTF-8',
|
||||
},
|
||||
{
|
||||
'key':'GBK',
|
||||
'value':'GBK',
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
classname: [{required: true, message: "请选择TCPClient", trigger: 'change'}],
|
||||
server: [{required: true, message: this.$t('api_test.request.tcp.server_cannot_be_empty'), trigger: 'blur'}],
|
||||
port: [{required: true, message: this.$t('commons.port_cannot_be_empty'), trigger: 'change'}],
|
||||
},
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
reportType(){
|
||||
this.request.reportType = this.reportType;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.currentProjectId = getCurrentProjectID();
|
||||
if (!this.request.parameters) {
|
||||
this.$set(this.request, 'parameters', []);
|
||||
this.request.parameters = [];
|
||||
}
|
||||
if (!this.request.tcpPreProcessor) {
|
||||
this.$set(this.request, 'tcpPreProcessor', new JSR223PreProcessor())
|
||||
}
|
||||
if(!this.request.connectEncoding){
|
||||
this.request.connectEncoding = "UTF-8";
|
||||
}
|
||||
this.getEnvironments();
|
||||
|
||||
if(this.request){
|
||||
if(!this.request.reportType){
|
||||
this.request.reportType = "raw";
|
||||
}else {
|
||||
if(this.request.reportType !== "json" && this.request.reportType !== "xml"&&this.request.reportType !== "raw"){
|
||||
this.request.reportType = "raw";
|
||||
}
|
||||
}
|
||||
this.reportType = this.request.reportType;
|
||||
|
||||
if(!this.request.xmlDataStruct){
|
||||
this.initXmlTableData();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addPre() {
|
||||
let jsr223PreProcessor = createComponent("JSR223PreProcessor");
|
||||
this.request.hashTree.push(jsr223PreProcessor);
|
||||
this.reload();
|
||||
},
|
||||
addPost() {
|
||||
let jsr223PostProcessor = createComponent("JSR223PostProcessor");
|
||||
this.request.hashTree.push(jsr223PostProcessor);
|
||||
this.reload();
|
||||
},
|
||||
addAssertions() {
|
||||
let assertions = new Assertions();
|
||||
this.request.hashTree.push(assertions);
|
||||
this.reload();
|
||||
},
|
||||
addExtract() {
|
||||
let jsonPostProcessor = new Extract();
|
||||
this.request.hashTree.push(jsonPostProcessor);
|
||||
this.reload();
|
||||
},
|
||||
remove(row) {
|
||||
let index = this.request.hashTree.indexOf(row);
|
||||
this.request.hashTree.splice(index, 1);
|
||||
this.reload();
|
||||
},
|
||||
copyRow(row) {
|
||||
let obj =JSON.parse(JSON.stringify(row));
|
||||
obj.id = getUUID();
|
||||
this.request.hashTree.push(obj);
|
||||
this.reload();
|
||||
},
|
||||
reload() {
|
||||
this.isReloadData = true
|
||||
this.$nextTick(() => {
|
||||
this.isReloadData = false
|
||||
})
|
||||
},
|
||||
validateApi() {
|
||||
if (this.currentProjectId === null) {
|
||||
this.$error(this.$t('api_test.select_project'), 2000);
|
||||
return;
|
||||
}
|
||||
this.$refs['basicForm'].validate();
|
||||
},
|
||||
saveApi() {
|
||||
this.basisData.method = this.basisData.protocol;
|
||||
this.$emit('saveApi', this.basisData);
|
||||
},
|
||||
runTest() {
|
||||
|
||||
},
|
||||
validate() {
|
||||
if (this.currentProjectId === null) {
|
||||
this.$error(this.$t('api_test.select_project'), 2000);
|
||||
return;
|
||||
}
|
||||
this.$refs['request'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$emit('callback');
|
||||
}
|
||||
})
|
||||
},
|
||||
getEnvironments() {
|
||||
if (this.currentProjectId) {
|
||||
this.environments = [];
|
||||
this.$get('/api/environment/list/' + this.currentProjectId, response => {
|
||||
this.environments = response.data;
|
||||
this.environments.forEach(environment => {
|
||||
parseEnvironment(environment);
|
||||
});
|
||||
this.initDataSource();
|
||||
});
|
||||
}
|
||||
},
|
||||
openEnvironmentConfig() {
|
||||
if (!this.currentProjectId) {
|
||||
this.$error(this.$t('api_test.select_project'));
|
||||
return;
|
||||
}
|
||||
this.$refs.environmentConfig.open(this.currentProjectId);
|
||||
},
|
||||
initDataSource() {
|
||||
for (let i in this.environments) {
|
||||
if (this.environments[i].id === this.request.environmentId) {
|
||||
this.databaseConfigsOptions = [];
|
||||
this.environments[i].config.databaseConfigs.forEach(item => {
|
||||
this.databaseConfigsOptions.push(item);
|
||||
})
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
environmentChange(value) {
|
||||
this.request.dataSource = undefined;
|
||||
for (let i in this.environments) {
|
||||
if (this.environments[i].id === value) {
|
||||
this.databaseConfigsOptions = [];
|
||||
this.environments[i].config.databaseConfigs.forEach(item => {
|
||||
this.databaseConfigsOptions.push(item);
|
||||
})
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
environmentConfigClose() {
|
||||
this.getEnvironments();
|
||||
},
|
||||
|
||||
changeReportType(){
|
||||
},
|
||||
|
||||
//以下是xml树形表格相关的方法
|
||||
updateXmlTableData(dataStruct){
|
||||
this.request.xmlDataStruct = dataStruct;
|
||||
},
|
||||
saveXmlTableData(dataStruct){
|
||||
let valedataResult = this.validateXmlDataStruct(dataStruct);
|
||||
if(valedataResult){
|
||||
this.request.xmlDataStruct = dataStruct;
|
||||
this.refreshXmlTable();
|
||||
}
|
||||
},
|
||||
validateXmlDataStruct(dataStruct){
|
||||
this.refreshXmlTableDataStruct(dataStruct);
|
||||
let result = this.checkXmlTableDataStructData(dataStruct);
|
||||
return result;
|
||||
},
|
||||
refreshXmlTableDataStruct(dataStruct){
|
||||
if(dataStruct && dataStruct.length > 0){
|
||||
dataStruct.forEach( row => {
|
||||
row.status = "";
|
||||
if(row.children == null || row.children.length === 0){
|
||||
row.children = [];
|
||||
}else if(row.children.length>0){
|
||||
this.refreshXmlTableDataStruct(row.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
checkXmlTableDataStructData(dataStruct){
|
||||
let allCheckResult = true;
|
||||
if(dataStruct && dataStruct.length > 0){
|
||||
for(let i = 0;i<dataStruct.length;i++){
|
||||
let row = dataStruct[i];
|
||||
allCheckResult = this.$refs.treeTable.validateRowData(row);
|
||||
if(allCheckResult){
|
||||
if(row.children != null && row.children.length > 0){
|
||||
allCheckResult = this.checkXmlTableDataStructData(row.children);
|
||||
if(!allCheckResult){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return allCheckResult;
|
||||
},
|
||||
initXmlTableData(){
|
||||
if(this.request){
|
||||
this.request.xmlDataStruct = [];
|
||||
this.refreshXmlTable();
|
||||
}
|
||||
},
|
||||
xmlTableDataPushRow(newRow){
|
||||
if(this.request){
|
||||
if(!this.request.xmlDataStruct){
|
||||
this.request.xmlDataStruct = [];
|
||||
}
|
||||
this.request.xmlDataStruct.push(newRow);
|
||||
this.refreshXmlTable();
|
||||
}
|
||||
},
|
||||
xmlTableDataRemoveRow(row){
|
||||
if(this.request){
|
||||
if(this.request.xmlDataStruct){
|
||||
this.removeFromDataStruct(this.request.xmlDataStruct,row);
|
||||
this.refreshXmlTable();
|
||||
}
|
||||
}
|
||||
},
|
||||
removeFromDataStruct(dataStruct,row){
|
||||
if(!dataStruct || dataStruct.length === 0){
|
||||
return;
|
||||
}
|
||||
let rowIndex = dataStruct.indexOf(row);
|
||||
if(rowIndex >= 0){
|
||||
dataStruct.splice(rowIndex,1);
|
||||
}else {
|
||||
dataStruct.forEach( itemData => {
|
||||
if(!itemData.children && itemData.children.length > 0){
|
||||
this.removeFromDataStruct(itemData.children,row);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
refreshXmlTable(){
|
||||
this.refreshedXmlTable = true
|
||||
this.$nextTick(() => {
|
||||
this.refreshedXmlTable = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tcp >>> .el-input-number {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.send-request {
|
||||
padding: 0px 0;
|
||||
height: 300px;
|
||||
border: 1px #DCDFE6 solid;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ms-left-cell {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.ms-left-buttion {
|
||||
margin: 6px 0px 8px 30px;
|
||||
}
|
||||
|
||||
/deep/ .el-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.ms-left-cell {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.ms-left-buttion {
|
||||
margin: 6px 0px 8px 30px;
|
||||
}
|
||||
|
||||
/deep/ .el-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/deep/ .instructions-icon {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
.request-tabs {
|
||||
margin: 20px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.other-config {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -33,7 +33,8 @@
|
|||
|
||||
<div v-if="api.method=='TCP'">
|
||||
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
|
||||
<ms-basis-parameters :request="api.request" @callback="runTest" ref="requestForm"/>
|
||||
<!-- <ms-basis-parameters :request="api.request" @callback="runTest" ref="requestForm"/>-->
|
||||
<ms-tcp-format-parameters :request="api.request" @callback="runTest" ref="requestForm"/>
|
||||
<!--返回结果-->
|
||||
<!-- HTTP 请求返回数据 -->
|
||||
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
|
||||
|
@ -74,7 +75,7 @@ import MsContainer from "../../../../common/components/MsContainer";
|
|||
import MsBottomContainer from "../BottomContainer";
|
||||
import MsRequestResultTail from "../response/RequestResultTail";
|
||||
import MsRun from "../Run";
|
||||
import MsBasisParameters from "../request/tcp/TcpBasisParameters";
|
||||
import MsTcpFormatParameters from "@/business/components/api/definition/components/request/tcp/TcpFormatParameters";
|
||||
import {REQ_METHOD} from "../../model/JsonData";
|
||||
import EnvironmentSelect from "../environment/EnvironmentSelect";
|
||||
import MsJmxStep from "../step/JmxStep";
|
||||
|
@ -92,7 +93,7 @@ export default {
|
|||
MsBottomContainer,
|
||||
MsRequestResultTail,
|
||||
MsRun,
|
||||
MsBasisParameters,
|
||||
MsTcpFormatParameters,
|
||||
"esbDefinition": esbDefinition.default,
|
||||
"esbDefinitionResponse": esbDefinitionResponse.default
|
||||
},
|
||||
|
|
|
@ -160,7 +160,7 @@ export default {
|
|||
if (apiTest.jmx.caseId) {
|
||||
this.$refs.basicConfig.importCase(apiTest.jmx);
|
||||
}
|
||||
if (JSON.stringify(apiTest.jmx.attachFiles) != "{}") {
|
||||
if (JSON.stringify(apiTest.jmx.attachFiles) !== "{}") {
|
||||
let attachFiles = [];
|
||||
for (let fileID in apiTest.jmx.attachFiles) {
|
||||
attachFiles.push(fileID);
|
||||
|
@ -171,6 +171,33 @@ export default {
|
|||
}
|
||||
this.active = '1';
|
||||
this.$store.commit("clearTest");
|
||||
}else {
|
||||
let scenarioJmxs = this.$store.state.scenarioJmxs;
|
||||
if(scenarioJmxs && scenarioJmxs.name){
|
||||
this.$set(this.test, "name", scenarioJmxs.name);
|
||||
if(scenarioJmxs.jmxs){
|
||||
scenarioJmxs.jmxs.forEach(item => {
|
||||
if (item.scenarioId) {
|
||||
this.$refs.basicConfig.importScenario(item.scenarioId);
|
||||
this.$refs.basicConfig.handleUpload();
|
||||
}
|
||||
if (item.caseId) {
|
||||
this.$refs.basicConfig.importCase(item);
|
||||
}
|
||||
if (JSON.stringify(item.attachFiles) !== "{}") {
|
||||
let attachFiles = [];
|
||||
for (let fileID in item.attachFiles) {
|
||||
attachFiles.push(fileID);
|
||||
}
|
||||
if (attachFiles.length > 0) {
|
||||
this.$refs.basicConfig.selectAttachFileById(attachFiles);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.active = '1';
|
||||
this.$store.commit("clearScenarioJmxs");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getTest(testId) {
|
||||
|
|
|
@ -669,6 +669,7 @@ export default {
|
|||
key: "Key",
|
||||
value: "Value",
|
||||
create_performance_test: "Create Performance Test",
|
||||
create_performance_test_batch: "Batch Create Performance Test",
|
||||
export_config: "Export",
|
||||
enable_validate_tip: "No request available",
|
||||
copy: "Copy Test",
|
||||
|
@ -760,6 +761,7 @@ export default {
|
|||
res_param: "Response content",
|
||||
batch_delete: "Batch deletion",
|
||||
delete_confirm: "Confirm deletion",
|
||||
batch_to_performance_confirm: "Confirm Batch Create Performance Test",
|
||||
delete_case_confirm: "Confirm case deletion",
|
||||
delete_confirm_step: "Confirm deletion step",
|
||||
assertions_rule: "Assertion rule",
|
||||
|
|
|
@ -668,6 +668,7 @@ export default {
|
|||
key: "键",
|
||||
value: "值",
|
||||
create_performance_test: "创建性能测试",
|
||||
create_performance_test_batch: "批量创建性能测试",
|
||||
export_config: "导出",
|
||||
enable_validate_tip: "没有可用请求",
|
||||
copy: "复制测试",
|
||||
|
@ -760,6 +761,7 @@ export default {
|
|||
res_param: "响应内容",
|
||||
batch_delete: "批量删除",
|
||||
delete_confirm: "确认删除接口",
|
||||
batch_to_performance_confirm: "确认批量创建性能测试",
|
||||
delete_case_confirm: "确认删除用例",
|
||||
delete_confirm_step: "确认删除步骤",
|
||||
assertions_rule: "断言规则",
|
||||
|
|
|
@ -668,6 +668,7 @@ export default {
|
|||
key: "鍵",
|
||||
value: "值",
|
||||
create_performance_test: "創建性能測試",
|
||||
create_performance_test_batch: "批量創建性能測試",
|
||||
export_config: "導出",
|
||||
enable_validate_tip: "沒有可用請求",
|
||||
copy: "復制測試",
|
||||
|
@ -760,6 +761,7 @@ export default {
|
|||
res_param: "響應內容",
|
||||
batch_delete: "批量刪除",
|
||||
delete_confirm: "確認刪除接口",
|
||||
batch_to_performance_confirm: "確認批量創建性能測試",
|
||||
delete_case_confirm: "確認刪除用例",
|
||||
delete_confirm_step: "確認刪除步驟",
|
||||
assertions_rule: "斷言規則",
|
||||
|
|
|
@ -9,6 +9,7 @@ Vue.use(Vuex)
|
|||
const state = {
|
||||
projectId: "",
|
||||
test: {},
|
||||
scenarioJmxs:{},
|
||||
versionSwitch: "new",
|
||||
isReadOnly: true,
|
||||
theme: undefined,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
const mutations = {
|
||||
setProjectId: (state, projectId) => state.projectId = projectId,
|
||||
setTest: (state, test) => state.test = test,
|
||||
setScenarioJmxs: (state, scenarioJmxs) => state.scenarioJmxs = scenarioJmxs,
|
||||
clearTest: state => state.test = {},
|
||||
clearScenarioJmxs:state => state.scenarioJmxs = {},
|
||||
setVersionSwitch: (state, value) => state.versionSwitch = value,
|
||||
setTheme: (state, value) => state.theme = value,
|
||||
|
||||
|
|
Loading…
Reference in New Issue