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 io.metersphere.api.dto.APIReportResult;
|
||||
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.ReferenceDTO;
|
||||
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
|
||||
import io.metersphere.api.dto.definition.*;
|
||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
import io.metersphere.api.dto.definition.request.assertions.document.DocumentElement;
|
||||
|
@ -394,4 +396,8 @@ public class ApiDefinitionController {
|
|||
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.mock.MockConfigRequestParams;
|
||||
import io.metersphere.api.mock.utils.MockApiUtils;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
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.dom4j.Document;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -26,6 +30,9 @@ import java.util.List;
|
|||
* @Description
|
||||
*/
|
||||
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) {
|
||||
String xmlString = "";
|
||||
try {
|
||||
|
@ -84,6 +91,51 @@ public class TcpTreeTableDataParser {
|
|||
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) {
|
||||
if (CollectionUtils.isEmpty(tcpDataList)) {
|
||||
return true;
|
||||
|
|
|
@ -13,6 +13,8 @@ import io.metersphere.api.dto.APIReportResult;
|
|||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.dto.automation.ApiScenarioRequest;
|
||||
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.definition.*;
|
||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
|
@ -2797,4 +2799,8 @@ public class ApiDefinitionService {
|
|||
List<ApiScenarioReferenceId> apiScenarioReferenceIds = apiScenarioReferenceIdMapper.selectByExample(apiScenarioReferenceIdExample);
|
||||
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_member_tip=[%s] must be current project member
|
||||
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_warning=No matching Mock expectation was found
|
||||
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
|
||||
update_api_case=Updated interface use case
|
||||
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=接口用例新建通知
|
||||
update_api_case=更新了接口用例
|
||||
api_case_update_notice=接口用例更新通知
|
||||
error_xml_struct=错误的xml数据
|
||||
|
|
|
@ -427,3 +427,4 @@ create_api_case=新建了接口用例
|
|||
api_case_create_notice=接口用例新建通知
|
||||
update_api_case=更新了接口用例
|
||||
api_case_update_notice=接口用例更新通知
|
||||
error_xml_struct=錯誤的xml數據
|
||||
|
|
|
@ -60,7 +60,6 @@
|
|||
<!-- 请求参数 -->
|
||||
<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-tcp-format-parameters :show-pre-script="true" :show-script="false" :request="request"
|
||||
ref="tcpFormatParameter"/>
|
||||
</div>
|
||||
|
|
|
@ -14,9 +14,8 @@
|
|||
<ms-api-variable :is-read-only="isReadOnly" :parameters="request.parameters"/>
|
||||
</el-tab-pane>
|
||||
<!--test-->
|
||||
|
||||
<!--query 参数-->
|
||||
<el-tab-pane v-if="isBodyShow" :label="$t('api_test.definition.document.request_body')" name="request">
|
||||
<el-tab-pane v-if="isBodyShow" :label="$t('api_test.definition.document.request_body')" name="request"
|
||||
v-loading="result.loading">
|
||||
<el-radio-group v-model="reportType" size="mini" style="margin: 10px 0px;">
|
||||
<el-radio :disabled="isReadOnly" label="json" @change="changeReportType">
|
||||
json
|
||||
|
@ -45,6 +44,10 @@
|
|||
<ms-code-edit mode="text" :read-only="isReadOnly" :data.sync="request.rawDataStruct"
|
||||
:modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
|
||||
</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>
|
||||
</el-tab-pane>
|
||||
|
||||
|
@ -63,7 +66,7 @@
|
|||
<el-input v-model="request.eolByte" size="small"/>
|
||||
</el-form-item>
|
||||
</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-input v-model="request.soLinger" size="small"/>
|
||||
</el-form-item>
|
||||
|
@ -98,33 +101,6 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
</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 :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>
|
||||
</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"
|
||||
:tab-type="'assertionsRule'" ref="assertionsRule"/>
|
||||
</el-tab-pane>
|
||||
|
@ -191,7 +168,7 @@ import ApiDefinitionStepButton from "../components/ApiDefinitionStepButton";
|
|||
import TcpXmlTable from "@/business/components/api/definition/components/complete/table/TcpXmlTable";
|
||||
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
|
||||
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 {
|
||||
|
@ -233,6 +210,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
spanNum: 24,
|
||||
result: {},
|
||||
activeName: "request",
|
||||
classes: TCPSampler.CLASSES,
|
||||
reportType: "xml",
|
||||
|
@ -316,6 +294,15 @@ export default {
|
|||
}
|
||||
},
|
||||
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() {
|
||||
if (this.activeName === 'preOperate') {
|
||||
this.$refs.preStep.filter();
|
||||
|
@ -596,4 +583,10 @@ export default {
|
|||
padding: 15px 0px;
|
||||
}
|
||||
|
||||
.ht-btn-add {
|
||||
border: 0px;
|
||||
margin-top: 10px;
|
||||
color: #783887;
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1170,6 +1170,9 @@ export default {
|
|||
hours: "H",
|
||||
},
|
||||
api_test: {
|
||||
buttons: {
|
||||
to_xml: "To xml",
|
||||
},
|
||||
case_jump_message: "The jump use case has been removed!",
|
||||
scenario_jump_message: "The jumped scene has been deleted!",
|
||||
is_continue: "Is continue",
|
||||
|
|
|
@ -1180,6 +1180,9 @@ export default {
|
|||
hours: "时",
|
||||
},
|
||||
api_test: {
|
||||
buttons: {
|
||||
to_xml: "转xml结构",
|
||||
},
|
||||
case_jump_message: "跳转的用例已经删除!",
|
||||
scenario_jump_message: "跳转的场景已经删除!",
|
||||
is_continue: "是否继续",
|
||||
|
|
|
@ -1177,6 +1177,9 @@ export default {
|
|||
hours: "時",
|
||||
},
|
||||
api_test: {
|
||||
buttons: {
|
||||
to_xml: "轉xml結構",
|
||||
},
|
||||
case_jump_message: "跳轉的用例已經刪除!",
|
||||
scenario_jump_message: "跳轉的場景已經刪除!",
|
||||
is_continue: "是否繼續",
|
||||
|
|
Loading…
Reference in New Issue