refactor: ESB功能优化-ESB接口测试,使用ESB数据格式展现

ESB功能优化-测试ESB接口时使用ESB数据格式展现
This commit is contained in:
song-tianyang 2021-05-13 15:22:43 +08:00 committed by 刘瑞斌
parent d68a62ddc7
commit a8241727eb
6 changed files with 230 additions and 171 deletions

View File

@ -16,6 +16,7 @@ import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.EsbApiParamService; import io.metersphere.api.service.EsbApiParamService;
import io.metersphere.api.service.EsbImportService; import io.metersphere.api.service.EsbImportService;
import io.metersphere.base.domain.ApiDefinition; import io.metersphere.base.domain.ApiDefinition;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs; import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.constants.RoleConstants;
@ -100,9 +101,9 @@ public class ApiDefinitionController {
@PostMapping(value = "/update", consumes = {"multipart/form-data"}) @PostMapping(value = "/update", consumes = {"multipart/form-data"})
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER}, logical = Logical.OR) @RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER}, logical = Logical.OR)
public void update(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) { public ApiDefinitionWithBLOBs update(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
checkPermissionService.checkProjectOwner(request.getProjectId()); checkPermissionService.checkProjectOwner(request.getProjectId());
apiDefinitionService.update(request, bodyFiles); return apiDefinitionService.update(request, bodyFiles);
} }
@GetMapping("/delete/{id}") @GetMapping("/delete/{id}")

View File

@ -173,7 +173,7 @@ public class ApiDefinitionService {
FileUtils.createBodyFiles(bodyUploadIds, bodyFiles); FileUtils.createBodyFiles(bodyUploadIds, bodyFiles);
} }
public void update(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) { public ApiDefinitionWithBLOBs update(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
if (request.getRequest() != null) { if (request.getRequest() != null) {
deleteFileByTestId(request.getRequest().getId()); deleteFileByTestId(request.getRequest().getId());
} }
@ -182,8 +182,9 @@ public class ApiDefinitionService {
if (StringUtils.equals(request.getProtocol(), "DUBBO")) { if (StringUtils.equals(request.getProtocol(), "DUBBO")) {
request.setMethod("dubbo://"); request.setMethod("dubbo://");
} }
updateTest(request); ApiDefinitionWithBLOBs returnModel = updateTest(request);
FileUtils.createBodyFiles(bodyUploadIds, bodyFiles); FileUtils.createBodyFiles(bodyUploadIds, bodyFiles);
return returnModel;
} }
public void delete(String apiId) { public void delete(String apiId) {
@ -274,7 +275,7 @@ public class ApiDefinitionService {
} }
private ApiDefinition updateTest(SaveApiDefinitionRequest request) { private ApiDefinitionWithBLOBs updateTest(SaveApiDefinitionRequest request) {
checkNameExist(request); checkNameExist(request);
if (StringUtils.equals(request.getMethod(), "ESB")) { if (StringUtils.equals(request.getMethod(), "ESB")) {
//ESB的接口类型数据采用TCP方式去发送并将方法类型改为TCP 并修改发送数据 //ESB的接口类型数据采用TCP方式去发送并将方法类型改为TCP 并修改发送数据
@ -546,6 +547,8 @@ public class ApiDefinitionService {
* @return * @return
*/ */
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) { public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
//检查是否是ESB请求ESB请求需要根据数据结构更换参数
request = esbApiParamService.checkIsEsbRequest(request);
int count = 100; int count = 100;
BaseSystemConfigDTO dto = systemParameterService.getBaseInfo(); BaseSystemConfigDTO dto = systemParameterService.getBaseInfo();
if (StringUtils.isNotEmpty(dto.getConcurrency())) { if (StringUtils.isNotEmpty(dto.getConcurrency())) {

View File

@ -5,17 +5,16 @@ import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.automation.EsbDataStruct; import io.metersphere.api.dto.automation.EsbDataStruct;
import io.metersphere.api.dto.automation.SaveApiScenarioRequest; import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
import io.metersphere.api.dto.automation.parse.EsbDataParser; import io.metersphere.api.dto.automation.parse.EsbDataParser;
import io.metersphere.api.dto.definition.ApiDefinitionResult; import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.ApiTestCaseResult;
import io.metersphere.api.dto.definition.SaveApiDefinitionRequest;
import io.metersphere.api.dto.definition.SaveApiTestCaseRequest;
import io.metersphere.api.dto.definition.request.MsTestElement; import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler; import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.EsbApiParamsExample; import io.metersphere.base.domain.EsbApiParamsExample;
import io.metersphere.base.domain.EsbApiParamsWithBLOBs; import io.metersphere.base.domain.EsbApiParamsWithBLOBs;
import io.metersphere.base.mapper.EsbApiParamsMapper; import io.metersphere.base.mapper.EsbApiParamsMapper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -400,4 +399,33 @@ public class EsbApiParamService {
} }
} }
} }
public RunDefinitionRequest checkIsEsbRequest(RunDefinitionRequest request) {
try {
//修改reqeust.parameters
//用户交互感受ESB的发送数据以报文模板为主框架同时前端不再有key-value的表格数据填充
//业务逻辑 发送ESB接口数据时使用报文模板中的数据同时报文模板中的${取值}目的是为了拼接数据结构(比如xml的子节点)
//代码实现: 此处打算解析前端传来的EsbDataStruct数据结构将数据结构按照报文模板中的${取值}为最高优先级组装keyValue对象这样Jmeter会自动拼装为合适的xml
if(request.getTestElement() != null ){
MsTestPlan testPlan = (MsTestPlan) request.getTestElement();
if(CollectionUtils.isNotEmpty(testPlan.getHashTree())){
for (MsTestElement testElement: testPlan.getHashTree()) {
if(CollectionUtils.isNotEmpty(testElement.getHashTree())){
for (MsTestElement apiElement:testElement.getHashTree()) {
if(apiElement instanceof MsTCPSampler){
MsTCPSampler tcpSampler = (MsTCPSampler) apiElement;
tcpSampler.setProtocol("ESB");
List<KeyValue> keyValueList = this.genKeyValueListByDataStruct(tcpSampler, tcpSampler.getEsbDataStruct());
tcpSampler.setParameters(keyValueList);
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return request;
}
} }

View File

@ -215,7 +215,7 @@
selectDataRange: 'all', selectDataRange: 'all',
showCasePage: true, showCasePage: true,
apiDefaultTab: 'default', apiDefaultTab: 'default',
currentProtocol: null, currentProtocol: 'HTTP',
currentModule: null, currentModule: null,
selectNodeIds: [], selectNodeIds: [],
currentApi: {}, currentApi: {},
@ -260,7 +260,7 @@
}); });
}, },
'$route'(to, from) { // ctrl s '$route'(to, from) { // ctrl s
if (to.path.indexOf('/api/definition') == -1) { if (to.path.indexOf('/api/definition') === -1) {
if (this.$refs && this.$refs.apiConfig) { if (this.$refs && this.$refs.apiConfig) {
this.$refs.apiConfig.forEach(item => { this.$refs.apiConfig.forEach(item => {
item.removeListener(); item.removeListener();
@ -299,7 +299,7 @@
}); // tab ctrl + s }); // tab ctrl + s
let tabs = this.apiTabs; let tabs = this.apiTabs;
let index = tabs.findIndex(item => item.name === tab.name); // tabindex let index = tabs.findIndex(item => item.name === tab.name); // tabindex
if (index != -1 && this.$refs.apiConfig[index - 1]) { if (index !== -1 && this.$refs.apiConfig[index - 1]) {
this.$refs.apiConfig[index - 1].addListener(); // tab ctrl + s index-1tab this.$refs.apiConfig[index - 1].addListener(); // tab ctrl + s index-1tab
} }
} }

View File

@ -101,9 +101,11 @@ export default {
runTest(data) { runTest(data) {
this.setParameters(data); this.setParameters(data);
let bodyFiles = this.getBodyUploadFiles(data); let bodyFiles = this.getBodyUploadFiles(data);
this.$fileUpload(this.reqUrl, null, bodyFiles, data, () => { this.$fileUpload(this.reqUrl, null, bodyFiles, data, response => {
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
this.reqUrl = "/api/definition/update"; this.reqUrl = "/api/definition/update";
let newData = response.data;
data.request = JSON.parse(newData.request);
this.$emit('runTest', data); this.$emit('runTest', data);
}); });
}, },

View File

@ -26,19 +26,32 @@
<environment-select :type="'TCP'" :current-data="api" :project-id="projectId"/> <environment-select :type="'TCP'" :current-data="api" :project-id="projectId"/>
</el-form-item> </el-form-item>
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- TCP 请求参数 -->
<ms-basis-parameters :request="api.request" @callback="runTest" ref="requestForm"/>
<!-- TCP 请求参数 -->
<!-- <p class="tip">{{$t('api_test.definition.request.req_param')}} </p>-->
<!-- <ms-basis-parameters :request="api.request" @callback="runTest" ref="requestForm"/>-->
<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"/>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
<ms-request-result-tail :response="responseData" ref="runResult"/>
</div>
<div v-else-if="api.method=='ESB'">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<esb-definition v-xpack v-if="showXpackCompnent" :show-script="true" :request="api.request" @callback="runTest" ref="requestForm"/>
</div>
</el-form> </el-form>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
<ms-request-result-tail :response="responseData" ref="runResult"/>
<ms-jmx-step :request="api.request" :response="responseData"/> <ms-jmx-step :request="api.request" :response="responseData"/>
<div v-if="api.method=='ESB'">
<p class="tip">{{$t('api_test.definition.request.res_param')}}</p>
<esb-definition-response v-xpack v-if="showXpackCompnent" :is-api-component="false" :show-options-button="false" :request="api.request" :response-data="responseData" />
</div>
</el-card> </el-card>
<!-- 加载用例 --> <!-- 加载用例 -->
@ -65,7 +78,9 @@ import MsBasisParameters from "../request/tcp/TcpBasisParameters";
import {REQ_METHOD} from "../../model/JsonData"; import {REQ_METHOD} from "../../model/JsonData";
import EnvironmentSelect from "../environment/EnvironmentSelect"; import EnvironmentSelect from "../environment/EnvironmentSelect";
import MsJmxStep from "../step/JmxStep"; import MsJmxStep from "../step/JmxStep";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const esbDefinition = (requireComponent!=null&&requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinition.vue") : {};
const esbDefinitionResponse = (requireComponent!=null&&requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinitionResponse.vue") : {};
export default { export default {
name: "RunTestTCPPage", name: "RunTestTCPPage",
components: { components: {
@ -77,168 +92,178 @@ export default {
MsBottomContainer, MsBottomContainer,
MsRequestResultTail, MsRequestResultTail,
MsRun, MsRun,
MsBasisParameters MsBasisParameters,
}, "esbDefinition": esbDefinition.default,
data() { "esbDefinitionResponse": esbDefinitionResponse.default
return { },
visible: false, data() {
api: {}, return {
loaded: false, visible: false,
loading: false, api: {},
currentRequest: {}, loaded: false,
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []}, loading: false,
reqOptions: REQ_METHOD, currentRequest: {},
environments: [], responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
refreshSign: "", reqOptions: REQ_METHOD,
createCase: "", environments: [],
rules: { refreshSign: "",
environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}], createCase: "",
}, rules: {
runData: [], environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}],
reportId: "", },
runData: [],
reportId: "",
showXpackCompnent:false,
}
},
props: {apiData: {}, currentProtocol: String,syncTabs: Array, projectId: String},
methods: {
handleCommand(e) {
switch (e) {
case "load_case":
return this.loadCase();
case "save_as_case":
return this.saveAsCase();
case "update_api":
return this.updateApi();
case "save_as_api":
return this.saveAsApi();
default:
return this.$refs['requestForm'].validate();
} }
}, },
props: {apiData: {}, currentProtocol: String,syncTabs: Array, projectId: String}, refresh(){
methods: { this.$emit('refresh');
handleCommand(e) { },
switch (e) { runTest() {
case "load_case": this.$refs['apiData'].validate((valid) => {
return this.loadCase(); if (valid) {
case "save_as_case": this.loading = true;
return this.saveAsCase(); this.api.request.name = this.api.id;
case "update_api": this.api.protocol = this.currentProtocol;
return this.updateApi(); this.runData = [];
case "save_as_api": this.runData.push(this.api.request);
return this.saveAsApi(); /*触发执行操作*/
default: this.reportId = getUUID().substring(0, 8);
return this.$refs['requestForm'].validate();
} }
}, })
refresh(){ },
this.$emit('refresh'); runRefresh(data) {
}, this.responseData = data;
runTest() { this.loading = false;
this.$refs['apiData'].validate((valid) => { },
if (valid) { saveAs() {
this.loading = true; this.$emit('saveAs', this.api);
this.api.request.name = this.api.id; },
this.api.protocol = this.currentProtocol; loadCase() {
this.runData = []; this.refreshSign = getUUID();
this.runData.push(this.api.request); this.$refs.caseList.open();
/*触发执行操作*/ this.visible = true;
this.reportId = getUUID().substring(0, 8); },
} apiCaseClose() {
}) this.visible = false;
}, },
runRefresh(data) { getBodyUploadFiles() {
this.responseData = data; let bodyUploadFiles = [];
this.loading = false; this.api.bodyUploadIds = [];
}, let request = this.api.request;
saveAs() { if (request.body) {
this.$emit('saveAs', this.api); request.body.kvs.forEach(param => {
}, if (param.files) {
loadCase() { param.files.forEach(item => {
this.refreshSign = getUUID(); if (item.file) {
this.$refs.caseList.open(); let fileId = getUUID().substring(0, 8);
this.visible = true; item.name = item.file.name;
}, item.id = fileId;
apiCaseClose() { this.api.bodyUploadIds.push(fileId);
this.visible = false; bodyUploadFiles.push(item.file);
}, }
getBodyUploadFiles() { });
let bodyUploadFiles = [];
this.api.bodyUploadIds = [];
let request = this.api.request;
if (request.body) {
request.body.kvs.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
let fileId = getUUID().substring(0, 8);
item.name = item.file.name;
item.id = fileId;
this.api.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
return bodyUploadFiles;
},
saveAsCase() {
this.createCase = getUUID();
this.$refs.caseList.open();
this.loaded = false;
},
saveAsApi() {
let data = {};
let req = this.api.request;
req.id = getUUID();
data.request = JSON.stringify(req);
data.method = this.api.method;
data.status = this.api.status;
data.userId = this.api.userId;
data.description = this.api.description;
this.$emit('saveAsApi', data);
this.$emit('refresh');
},
updateApi() {
let url = "/api/definition/update";
let bodyFiles = this.getBodyUploadFiles();
this.$fileUpload(url, null, bodyFiles, this.api, () => {
this.$success(this.$t('commons.save_success'));
if (this.syncTabs.indexOf(this.api.id) === -1) {
this.syncTabs.push(this.api.id);
}
this.$emit('saveApi', this.api);
});
},
selectTestCase(item) {
if (item != null) {
this.api.request = item.request;
} else {
this.api.request = this.currentRequest;
}
},
getResult() {
let url = "/api/definition/report/getReport/" + this.api.id;
this.$get(url, response => {
if (response.data) {
let data = JSON.parse(response.data.content);
this.responseData = data;
} }
}); });
} }
return bodyUploadFiles;
}, },
created() { saveAsCase() {
// this.createCase = getUUID();
this.api = JSON.parse(JSON.stringify(this.apiData)); this.$refs.caseList.open();
this.api.protocol = this.currentProtocol; this.loaded = false;
this.currentRequest = this.api.request; },
this.getResult(); saveAsApi() {
let data = {};
let req = this.api.request;
req.id = getUUID();
data.request = JSON.stringify(req);
data.method = this.api.method;
data.status = this.api.status;
data.userId = this.api.userId;
data.description = this.api.description;
this.$emit('saveAsApi', data);
this.$emit('refresh');
},
updateApi() {
let url = "/api/definition/update";
let bodyFiles = this.getBodyUploadFiles();
if(this.api.method==='ESB'){
this.api.esbDataStruct = JSON.stringify(this.api.request.esbDataStruct);
this.api.backEsbDataStruct = JSON.stringify(this.api.request.backEsbDataStruct);
}
this.$fileUpload(url, null, bodyFiles, this.api, () => {
this.$success(this.$t('commons.save_success'));
if (this.syncTabs.indexOf(this.api.id) === -1) {
this.syncTabs.push(this.api.id);
}
this.$emit('saveApi', this.api);
});
},
selectTestCase(item) {
if (item != null) {
this.api.request = item.request;
} else {
this.api.request = this.currentRequest;
}
},
getResult() {
let url = "/api/definition/report/getReport/" + this.api.id;
this.$get(url, response => {
if (response.data) {
let data = JSON.parse(response.data.content);
this.responseData = data;
}
});
}
},
created() {
//
this.api = JSON.parse(JSON.stringify(this.apiData));
this.api.protocol = this.currentProtocol;
this.currentRequest = this.api.request;
this.getResult();
if (requireComponent != null && JSON.stringify(esbDefinition) !== '{}') {
this.showXpackCompnent = true;
} }
} }
}
</script> </script>
<style scoped> <style scoped>
.ms-htt-width { .ms-htt-width {
width: 350px; width: 350px;
} }
.environment-button { .environment-button {
margin-left: 20px; margin-left: 20px;
padding: 7px; padding: 7px;
} }
.tip { .tip {
padding: 3px 5px; padding: 3px 5px;
font-size: 16px; font-size: 16px;
border-radius: 4px; border-radius: 4px;
border-left: 4px solid #783887; border-left: 4px solid #783887;
} }
/deep/ .el-drawer { /deep/ .el-drawer {
overflow: auto; overflow: auto;
} }
</style> </style>