feat(接口测试): 接口测试的TCP请求支持一键把xml文本格式转换成表格格式
--story=1006595 --user=宋天阳 【成都银行】支持一键把xml文本格式转换成表格格式 https://www.tapd.cn/55049933/s/1233105
This commit is contained in:
parent
f089e943b5
commit
3ced82ad63
|
@ -4,8 +4,10 @@ import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import io.metersphere.api.dto.APIReportResult;
|
import io.metersphere.api.dto.APIReportResult;
|
||||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||||
|
import io.metersphere.api.dto.ParseTreeDataDTO;
|
||||||
import io.metersphere.api.dto.automation.ApiScenarioRequest;
|
import io.metersphere.api.dto.automation.ApiScenarioRequest;
|
||||||
import io.metersphere.api.dto.automation.ReferenceDTO;
|
import io.metersphere.api.dto.automation.ReferenceDTO;
|
||||||
|
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
|
||||||
import io.metersphere.api.dto.definition.*;
|
import io.metersphere.api.dto.definition.*;
|
||||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||||
import io.metersphere.api.dto.definition.request.assertions.document.DocumentElement;
|
import io.metersphere.api.dto.definition.request.assertions.document.DocumentElement;
|
||||||
|
@ -394,4 +396,8 @@ public class ApiDefinitionController {
|
||||||
return apiDefinitionService.getCitedScenarioCount(definitionId);
|
return apiDefinitionService.getCitedScenarioCount(definitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/raw-to-xml")
|
||||||
|
public List<TcpTreeTableDataStruct> rawToXml(@RequestBody ParseTreeDataDTO parseTreeDataDTO) {
|
||||||
|
return apiDefinitionService.rawToXml(parseTreeDataDTO.getStringData());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package io.metersphere.api.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ParseTreeDataDTO {
|
||||||
|
private String stringData;
|
||||||
|
}
|
|
@ -5,19 +5,23 @@ import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
|
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
|
||||||
import io.metersphere.api.dto.mock.MockConfigRequestParams;
|
import io.metersphere.api.dto.mock.MockConfigRequestParams;
|
||||||
import io.metersphere.api.mock.utils.MockApiUtils;
|
import io.metersphere.api.mock.utils.MockApiUtils;
|
||||||
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
import io.metersphere.commons.utils.XMLUtils;
|
import io.metersphere.commons.utils.XMLUtils;
|
||||||
|
import io.metersphere.i18n.Translator;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
import org.dom4j.DocumentHelper;
|
import org.dom4j.DocumentHelper;
|
||||||
|
import org.dom4j.Element;
|
||||||
import org.dom4j.io.OutputFormat;
|
import org.dom4j.io.OutputFormat;
|
||||||
import org.dom4j.io.XMLWriter;
|
import org.dom4j.io.XMLWriter;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,6 +30,9 @@ import java.util.List;
|
||||||
* @Description
|
* @Description
|
||||||
*/
|
*/
|
||||||
public class TcpTreeTableDataParser {
|
public class TcpTreeTableDataParser {
|
||||||
|
public static final String DATA_TYPE_STRING = "string";
|
||||||
|
public static final String DATA_TYPE_OBJECT = "object";
|
||||||
|
|
||||||
public static String treeTableData2Xml(List<TcpTreeTableDataStruct> treeDataList) {
|
public static String treeTableData2Xml(List<TcpTreeTableDataStruct> treeDataList) {
|
||||||
String xmlString = "";
|
String xmlString = "";
|
||||||
try {
|
try {
|
||||||
|
@ -84,6 +91,51 @@ public class TcpTreeTableDataParser {
|
||||||
return xmlString;
|
return xmlString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<TcpTreeTableDataStruct> xml2TreeTableData(String xmlString) {
|
||||||
|
List<TcpTreeTableDataStruct> returnList = new ArrayList<>();
|
||||||
|
Document document = XMLUtils.stringToDocument(xmlString);
|
||||||
|
if (document != null) {
|
||||||
|
Element rootElement = document.getRootElement();
|
||||||
|
TcpTreeTableDataStruct struct = new TcpTreeTableDataStruct();
|
||||||
|
struct.init();
|
||||||
|
struct.setName(rootElement.getName());
|
||||||
|
List<Element> elements = rootElement.elements();
|
||||||
|
if (CollectionUtils.isEmpty(elements)) {
|
||||||
|
struct.setValue(rootElement.getStringValue());
|
||||||
|
struct.setType(TcpTreeTableDataParser.DATA_TYPE_STRING);
|
||||||
|
} else {
|
||||||
|
struct.setType(TcpTreeTableDataParser.DATA_TYPE_OBJECT);
|
||||||
|
struct.setChildren(docElement2TreeTableData(elements));
|
||||||
|
}
|
||||||
|
returnList.add(struct);
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(returnList)) {
|
||||||
|
MSException.throwException(Translator.get("error_xml_struct"));
|
||||||
|
}
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<TcpTreeTableDataStruct> docElement2TreeTableData(List<Element> elements) {
|
||||||
|
List<TcpTreeTableDataStruct> returnList = new ArrayList<>();
|
||||||
|
if (CollectionUtils.isNotEmpty(elements)) {
|
||||||
|
elements.forEach(element -> {
|
||||||
|
TcpTreeTableDataStruct struct = new TcpTreeTableDataStruct();
|
||||||
|
struct.init();
|
||||||
|
struct.setName(element.getName());
|
||||||
|
List<Element> children = element.elements();
|
||||||
|
if (CollectionUtils.isEmpty(children)) {
|
||||||
|
struct.setValue(element.getStringValue());
|
||||||
|
struct.setType(TcpTreeTableDataParser.DATA_TYPE_STRING);
|
||||||
|
} else {
|
||||||
|
struct.setType(TcpTreeTableDataParser.DATA_TYPE_OBJECT);
|
||||||
|
struct.setChildren(docElement2TreeTableData(children));
|
||||||
|
}
|
||||||
|
returnList.add(struct);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isMatchTreeTableData(JSONObject sourceObj, List<TcpTreeTableDataStruct> tcpDataList) {
|
public static boolean isMatchTreeTableData(JSONObject sourceObj, List<TcpTreeTableDataStruct> tcpDataList) {
|
||||||
if (CollectionUtils.isEmpty(tcpDataList)) {
|
if (CollectionUtils.isEmpty(tcpDataList)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -13,6 +13,8 @@ import io.metersphere.api.dto.APIReportResult;
|
||||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||||
import io.metersphere.api.dto.automation.ApiScenarioRequest;
|
import io.metersphere.api.dto.automation.ApiScenarioRequest;
|
||||||
import io.metersphere.api.dto.automation.ReferenceDTO;
|
import io.metersphere.api.dto.automation.ReferenceDTO;
|
||||||
|
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
|
||||||
|
import io.metersphere.api.dto.automation.parse.TcpTreeTableDataParser;
|
||||||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||||
import io.metersphere.api.dto.definition.*;
|
import io.metersphere.api.dto.definition.*;
|
||||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||||
|
@ -2797,4 +2799,8 @@ public class ApiDefinitionService {
|
||||||
List<ApiScenarioReferenceId> apiScenarioReferenceIds = apiScenarioReferenceIdMapper.selectByExample(apiScenarioReferenceIdExample);
|
List<ApiScenarioReferenceId> apiScenarioReferenceIds = apiScenarioReferenceIdMapper.selectByExample(apiScenarioReferenceIdExample);
|
||||||
return apiScenarioReferenceIds.size();
|
return apiScenarioReferenceIds.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TcpTreeTableDataStruct> rawToXml(String rawData) {
|
||||||
|
return TcpTreeTableDataParser.xml2TreeTableData(rawData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,7 +327,7 @@ custom_field_float_tip=[%s] must be number
|
||||||
custom_field_int_tip=[%s] must be integer
|
custom_field_int_tip=[%s] must be integer
|
||||||
custom_field_member_tip=[%s] must be current project member
|
custom_field_member_tip=[%s] must be current project member
|
||||||
custom_field_select_tip=[%s] must be %s
|
custom_field_select_tip=[%s] must be %s
|
||||||
no_legitimate_case_tip =Import fails without legitimate use cases!
|
no_legitimate_case_tip=Import fails without legitimate use cases!
|
||||||
# mock
|
# mock
|
||||||
mock_warning=No matching Mock expectation was found
|
mock_warning=No matching Mock expectation was found
|
||||||
zentao_test_type_error=invalid Zentao request
|
zentao_test_type_error=invalid Zentao request
|
||||||
|
@ -429,3 +429,4 @@ create_api_case=New interface use case
|
||||||
api_case_create_notice=Interface use case new notification
|
api_case_create_notice=Interface use case new notification
|
||||||
update_api_case=Updated interface use case
|
update_api_case=Updated interface use case
|
||||||
api_case_update_notice=Interface use case update notification
|
api_case_update_notice=Interface use case update notification
|
||||||
|
error_xml_struct=Data is not xml
|
|
@ -428,3 +428,4 @@ create_api_case=新建了接口用例
|
||||||
api_case_create_notice=接口用例新建通知
|
api_case_create_notice=接口用例新建通知
|
||||||
update_api_case=更新了接口用例
|
update_api_case=更新了接口用例
|
||||||
api_case_update_notice=接口用例更新通知
|
api_case_update_notice=接口用例更新通知
|
||||||
|
error_xml_struct=错误的xml数据
|
||||||
|
|
|
@ -427,3 +427,4 @@ create_api_case=新建了接口用例
|
||||||
api_case_create_notice=接口用例新建通知
|
api_case_create_notice=接口用例新建通知
|
||||||
update_api_case=更新了接口用例
|
update_api_case=更新了接口用例
|
||||||
api_case_update_notice=接口用例更新通知
|
api_case_update_notice=接口用例更新通知
|
||||||
|
error_xml_struct=錯誤的xml數據
|
||||||
|
|
|
@ -60,7 +60,6 @@
|
||||||
<!-- 请求参数 -->
|
<!-- 请求参数 -->
|
||||||
<div v-if="apiProtocol=='TCP'">
|
<div v-if="apiProtocol=='TCP'">
|
||||||
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
|
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
|
||||||
<!-- <ms-basis-parameters :show-script="false" :request="request"/>-->
|
|
||||||
<ms-tcp-format-parameters :show-pre-script="true" :show-script="false" :request="request"
|
<ms-tcp-format-parameters :show-pre-script="true" :show-script="false" :request="request"
|
||||||
ref="tcpFormatParameter"/>
|
ref="tcpFormatParameter"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,9 +14,8 @@
|
||||||
<ms-api-variable :is-read-only="isReadOnly" :parameters="request.parameters"/>
|
<ms-api-variable :is-read-only="isReadOnly" :parameters="request.parameters"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<!--test-->
|
<!--test-->
|
||||||
|
<el-tab-pane v-if="isBodyShow" :label="$t('api_test.definition.document.request_body')" name="request"
|
||||||
<!--query 参数-->
|
v-loading="result.loading">
|
||||||
<el-tab-pane v-if="isBodyShow" :label="$t('api_test.definition.document.request_body')" name="request">
|
|
||||||
<el-radio-group v-model="reportType" size="mini" style="margin: 10px 0px;">
|
<el-radio-group v-model="reportType" size="mini" style="margin: 10px 0px;">
|
||||||
<el-radio :disabled="isReadOnly" label="json" @change="changeReportType">
|
<el-radio :disabled="isReadOnly" label="json" @change="changeReportType">
|
||||||
json
|
json
|
||||||
|
@ -45,6 +44,10 @@
|
||||||
<ms-code-edit mode="text" :read-only="isReadOnly" :data.sync="request.rawDataStruct"
|
<ms-code-edit mode="text" :read-only="isReadOnly" :data.sync="request.rawDataStruct"
|
||||||
:modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
|
:modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
|
||||||
</div>
|
</div>
|
||||||
|
<el-button class="ht-btn-add" size="mini" p="$t('commons.add')" icon="el-icon-circle-plus-outline"
|
||||||
|
@click="toXml">
|
||||||
|
{{ $t("api_test.buttons.to_xml") }}
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
@ -63,7 +66,7 @@
|
||||||
<el-input v-model="request.eolByte" size="small"/>
|
<el-input v-model="request.eolByte" size="small"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6" label-width="80px" >
|
<el-col :span="6" label-width="80px">
|
||||||
<el-form-item :label="$t('api_test.request.tcp.so_linger')" prop="soLinger" label-width="120px">
|
<el-form-item :label="$t('api_test.request.tcp.so_linger')" prop="soLinger" label-width="120px">
|
||||||
<el-input v-model="request.soLinger" size="small"/>
|
<el-input v-model="request.soLinger" size="small"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -98,33 +101,6 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- <el-col :span="12">-->
|
|
||||||
|
|
||||||
<!-- </el-col>-->
|
|
||||||
<!-- </el-row>-->
|
|
||||||
<!-- <el-row :gutter="20">-->
|
|
||||||
<!-- <el-col :span="12">-->
|
|
||||||
|
|
||||||
<!-- </el-col>-->
|
|
||||||
<!-- <el-col :span="12">-->
|
|
||||||
|
|
||||||
<!-- </el-col>-->
|
|
||||||
<!-- </el-row>-->
|
|
||||||
<!-- <el-row :gutter="10" style="margin-left: 30px">-->
|
|
||||||
<!-- <el-col :span="6">-->
|
|
||||||
|
|
||||||
<!-- </el-col>-->
|
|
||||||
<!-- <el-col :span="6">-->
|
|
||||||
|
|
||||||
<!-- </el-col>-->
|
|
||||||
<!-- <el-col :span="6">-->
|
|
||||||
|
|
||||||
<!-- </el-col>-->
|
|
||||||
<!-- <el-col :span="6">-->
|
|
||||||
|
|
||||||
<!-- </el-col>-->
|
|
||||||
<!-- </el-row>-->
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<!-- 脚本步骤/断言步骤 -->
|
<!-- 脚本步骤/断言步骤 -->
|
||||||
<el-tab-pane :label="$t('api_test.definition.request.pre_operation')" name="preOperate" v-if="showScript">
|
<el-tab-pane :label="$t('api_test.definition.request.pre_operation')" name="preOperate" v-if="showScript">
|
||||||
|
@ -160,7 +136,8 @@
|
||||||
<div class="el-step__icon-inner">{{ request.ruleSize }}</div>
|
<div class="el-step__icon-inner">{{ request.ruleSize }}</div>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
<ms-jmx-step :request="request" :apiId="request.id" protocol="TCP" :scenario-id="scenarioId" :response="response"
|
<ms-jmx-step :request="request" :apiId="request.id" protocol="TCP" :scenario-id="scenarioId"
|
||||||
|
:response="response"
|
||||||
@reload="reloadBody"
|
@reload="reloadBody"
|
||||||
:tab-type="'assertionsRule'" ref="assertionsRule"/>
|
:tab-type="'assertionsRule'" ref="assertionsRule"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
@ -191,7 +168,7 @@ import ApiDefinitionStepButton from "../components/ApiDefinitionStepButton";
|
||||||
import TcpXmlTable from "@/business/components/api/definition/components/complete/table/TcpXmlTable";
|
import TcpXmlTable from "@/business/components/api/definition/components/complete/table/TcpXmlTable";
|
||||||
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
|
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
|
||||||
import MsJmxStep from "../../step/JmxStep";
|
import MsJmxStep from "../../step/JmxStep";
|
||||||
import {stepCompute, hisDataProcessing} from "@/business/components/api/definition/api-definition";
|
import {hisDataProcessing, stepCompute} from "@/business/components/api/definition/api-definition";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -233,6 +210,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
spanNum: 24,
|
spanNum: 24,
|
||||||
|
result: {},
|
||||||
activeName: "request",
|
activeName: "request",
|
||||||
classes: TCPSampler.CLASSES,
|
classes: TCPSampler.CLASSES,
|
||||||
reportType: "xml",
|
reportType: "xml",
|
||||||
|
@ -316,6 +294,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
toXml() {
|
||||||
|
let url = "/api/definition/raw-to-xml";
|
||||||
|
this.result = this.$post(url, {"stringData": this.request.rawDataStruct}, response => {
|
||||||
|
if (response.data) {
|
||||||
|
this.request.xmlDataStruct = response.data;
|
||||||
|
this.reportType = "xml";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
tabClick() {
|
tabClick() {
|
||||||
if (this.activeName === 'preOperate') {
|
if (this.activeName === 'preOperate') {
|
||||||
this.$refs.preStep.filter();
|
this.$refs.preStep.filter();
|
||||||
|
@ -596,4 +583,10 @@ export default {
|
||||||
padding: 15px 0px;
|
padding: 15px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ht-btn-add {
|
||||||
|
border: 0px;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #783887;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1170,6 +1170,9 @@ export default {
|
||||||
hours: "H",
|
hours: "H",
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
|
buttons: {
|
||||||
|
to_xml: "To xml",
|
||||||
|
},
|
||||||
case_jump_message: "The jump use case has been removed!",
|
case_jump_message: "The jump use case has been removed!",
|
||||||
scenario_jump_message: "The jumped scene has been deleted!",
|
scenario_jump_message: "The jumped scene has been deleted!",
|
||||||
is_continue: "Is continue",
|
is_continue: "Is continue",
|
||||||
|
|
|
@ -1180,6 +1180,9 @@ export default {
|
||||||
hours: "时",
|
hours: "时",
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
|
buttons: {
|
||||||
|
to_xml: "转xml结构",
|
||||||
|
},
|
||||||
case_jump_message: "跳转的用例已经删除!",
|
case_jump_message: "跳转的用例已经删除!",
|
||||||
scenario_jump_message: "跳转的场景已经删除!",
|
scenario_jump_message: "跳转的场景已经删除!",
|
||||||
is_continue: "是否继续",
|
is_continue: "是否继续",
|
||||||
|
|
|
@ -1177,6 +1177,9 @@ export default {
|
||||||
hours: "時",
|
hours: "時",
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
|
buttons: {
|
||||||
|
to_xml: "轉xml結構",
|
||||||
|
},
|
||||||
case_jump_message: "跳轉的用例已經刪除!",
|
case_jump_message: "跳轉的用例已經刪除!",
|
||||||
scenario_jump_message: "跳轉的場景已經刪除!",
|
scenario_jump_message: "跳轉的場景已經刪除!",
|
||||||
is_continue: "是否繼續",
|
is_continue: "是否繼續",
|
||||||
|
|
Loading…
Reference in New Issue