feat(系统设置): 自定义函数测试执行
This commit is contained in:
parent
4ab568610b
commit
2d7d360ec4
|
@ -2,6 +2,7 @@ package io.metersphere.controller;
|
|||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.base.domain.CustomFunction;
|
||||
import io.metersphere.base.domain.CustomFunctionWithBLOBs;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
|
@ -54,4 +55,9 @@ public class CustomFunctionController {
|
|||
public CustomFunctionWithBLOBs get(@PathVariable String id) {
|
||||
return customFunctionService.get(id);
|
||||
}
|
||||
|
||||
@PostMapping("/run")
|
||||
public String run(@RequestBody RunDefinitionRequest request) {
|
||||
return customFunctionService.run(request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
package io.metersphere.service;
|
||||
|
||||
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.CustomFunction;
|
||||
import io.metersphere.base.domain.CustomFunctionExample;
|
||||
import io.metersphere.base.domain.CustomFunctionWithBLOBs;
|
||||
import io.metersphere.base.mapper.CustomFunctionMapper;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.controller.request.CustomFunctionRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -28,6 +33,8 @@ public class CustomFunctionService {
|
|||
|
||||
@Resource
|
||||
private CustomFunctionMapper customFunctionMapper;
|
||||
@Resource
|
||||
private JMeterService jMeterService;
|
||||
|
||||
public CustomFunctionWithBLOBs save(CustomFunctionRequest request) {
|
||||
request.setId(UUID.randomUUID().toString());
|
||||
|
@ -106,4 +113,13 @@ public class CustomFunctionService {
|
|||
}
|
||||
return customFunctionMapper.selectByPrimaryKey(id);
|
||||
}
|
||||
|
||||
public String run(RunDefinitionRequest request) {
|
||||
ParameterConfig config = new ParameterConfig();
|
||||
config.setProjectId(request.getProjectId());
|
||||
HashTree hashTree = request.getTestElement().generateHashTree(config);
|
||||
String runMode = ApiRunMode.DEFINITION.name();
|
||||
jMeterService.runLocal(request.getId(), hashTree, request.getReportId(), runMode);
|
||||
return request.getId();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,25 +49,34 @@
|
|||
ref="codeEdit"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'执行结果'" name="result">
|
||||
执行结果
|
||||
<div v-loading="runResult.loading">
|
||||
<ms-code-edit :mode="'text'" :data.sync="console" v-if="isResultAlive" height="330px" ref="funcResult"/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4" class="script-index">
|
||||
<ms-dropdown :default-command="form.type" :commands="languages" @command="languageChange"/>
|
||||
<div class="template-title">{{ $t('api_test.request.processor.code_template') }}</div>
|
||||
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
|
||||
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{ template.title }}</el-link>
|
||||
<div style="margin-top: -25px; margin-left: 10px;">
|
||||
<div style="margin-bottom: 10px;">
|
||||
<el-button type="primary" size="mini" style="width: 70px;" @click="handleTest" :disabled="runResult.loading">测试</el-button>
|
||||
</div>
|
||||
<ms-dropdown :default-command="form.type" :commands="languages" @command="languageChange"/>
|
||||
<div class="template-title">{{ $t('api_test.request.processor.code_template') }}</div>
|
||||
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
|
||||
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{ template.title }}</el-link>
|
||||
</div>
|
||||
<el-link href="https://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PostProcessor"
|
||||
target="componentReferenceDoc" style="margin-top: 10px"
|
||||
type="primary">{{ $t('commons.reference_documentation') }}
|
||||
</el-link>
|
||||
</div>
|
||||
<el-link href="https://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PostProcessor"
|
||||
target="componentReferenceDoc" style="margin-top: 10px"
|
||||
type="primary">{{ $t('commons.reference_documentation') }}
|
||||
</el-link>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<!-- 执行组件 -->
|
||||
<function-run :report-id="reportId" :run-data="runData" @runRefresh="runRefresh" @errorRefresh="errorRefresh"/>
|
||||
</div>
|
||||
<template v-slot:footer>
|
||||
<el-button @click="close" size="medium">{{ $t('commons.cancel') }}</el-button>
|
||||
|
@ -84,25 +93,38 @@ import FunctionParams from "@/business/components/settings/project/function/Func
|
|||
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
|
||||
import MsDropdown from "@/business/components/common/components/MsDropdown";
|
||||
import {splicingCustomFunc} from "@/business/components/settings/project/function/custom_function";
|
||||
import MsRun from "@/business/components/api/automation/scenario/DebugRun";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
import {JSR223Processor} from "@/business/components/api/definition/model/ApiTestModel";
|
||||
import FunctionRun from "@/business/components/settings/project/function/FunctionRun";
|
||||
|
||||
export default {
|
||||
name: "EditFunction",
|
||||
components: {
|
||||
FunctionRun,
|
||||
MsCodeEdit,
|
||||
FunctionParams,
|
||||
MsInputTag,
|
||||
MsDropdown
|
||||
MsDropdown,
|
||||
MsRun
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
result: {},
|
||||
runResult: {
|
||||
loading: false
|
||||
},
|
||||
reportId: "",
|
||||
runData: [],
|
||||
isStop: false,
|
||||
dialogCreateTitle: "创建函数",
|
||||
dialogUpdateTitle: "更新函数",
|
||||
activeName: 'code',
|
||||
dialogTitle: "",
|
||||
isCodeEditAlive: true,
|
||||
isResultAlive: true,
|
||||
isFormAlive: true,
|
||||
form: {
|
||||
params: [],
|
||||
|
@ -179,6 +201,10 @@ export default {
|
|||
disabled: this.isPreProcessor
|
||||
}
|
||||
],
|
||||
response: {},
|
||||
request: {},
|
||||
debug: true,
|
||||
console: "无执行结果"
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -204,6 +230,7 @@ export default {
|
|||
params.join(",\s");
|
||||
}
|
||||
}
|
||||
// todo 参数拼接问题 删除参数 逗号未去除
|
||||
return params;
|
||||
},
|
||||
splicingFunc() {
|
||||
|
@ -215,6 +242,7 @@ export default {
|
|||
this.reloadCodeEdit();
|
||||
},
|
||||
open(data) {
|
||||
this.activeName = "code";
|
||||
this.visible = true;
|
||||
this.form.type = "beanshell";
|
||||
if (data && data.id) {
|
||||
|
@ -248,6 +276,7 @@ export default {
|
|||
type: "beanshell",
|
||||
params: [{}]
|
||||
};
|
||||
this.console = "无执行结果";
|
||||
this.visible = false;
|
||||
},
|
||||
languageChange(language) {
|
||||
|
@ -274,6 +303,10 @@ export default {
|
|||
this.isCodeEditAlive = false;
|
||||
this.$nextTick(() => (this.isCodeEditAlive = true));
|
||||
},
|
||||
reloadResult() {
|
||||
this.isResultAlive = false;
|
||||
this.$nextTick(() => (this.isResultAlive = true));
|
||||
},
|
||||
submit() {
|
||||
let param = Object.assign({}, this.form);
|
||||
param.params = JSON.stringify(this.form.params);
|
||||
|
@ -298,6 +331,29 @@ export default {
|
|||
this.$emit("refresh");
|
||||
this.$success(this.$t('commons.modify_success'));
|
||||
})
|
||||
},
|
||||
handleTest() {
|
||||
this.activeName = "result";
|
||||
this.console = "无执行结果";
|
||||
this.reloadResult();
|
||||
this.runResult.loading = true;
|
||||
|
||||
let jSR223Processor = new JSR223Processor({
|
||||
script: this.form.script
|
||||
});
|
||||
jSR223Processor.id = getUUID().substring(0, 8);
|
||||
this.runData = [];
|
||||
this.runData.push(jSR223Processor);
|
||||
this.reportId = getUUID().substring(0, 8);
|
||||
},
|
||||
runRefresh(data) {
|
||||
this.response = data;
|
||||
this.console = this.response.responseResult.console;
|
||||
this.runResult.loading = false;
|
||||
this.reloadResult();
|
||||
},
|
||||
errorRefresh() {
|
||||
this.runResult.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -308,6 +364,7 @@ export default {
|
|||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
/* 滚动条样式 */
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<span></span>
|
||||
</template>
|
||||
<script>
|
||||
import {getCurrentProjectID, strMapToObj} from "@/common/js/utils";
|
||||
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
|
||||
import TestPlan from "@/business/components/api/definition/components/jmeter/components/test-plan";
|
||||
import ThreadGroup from "@/business/components/api/definition/components/jmeter/components/thread-group";
|
||||
|
||||
export default {
|
||||
name: 'FunctionRun',
|
||||
components: {},
|
||||
props: {
|
||||
environment: Object,
|
||||
debug: Boolean,
|
||||
reportId: String,
|
||||
runData: Array,
|
||||
type: String,
|
||||
envMap: Map,
|
||||
isStop: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false,
|
||||
runId: "",
|
||||
reqNumber: 0,
|
||||
websocket: {}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
// 初始化
|
||||
reportId() {
|
||||
this.run()
|
||||
},
|
||||
isStop() {
|
||||
if (!this.isStop && this.websocket && this.websocket.close instanceof Function) {
|
||||
this.websocket.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initWebSocket() {
|
||||
let protocol = "ws://";
|
||||
if (window.location.protocol === 'https:') {
|
||||
protocol = "wss://";
|
||||
}
|
||||
const uri = protocol + window.location.host + "/api/definition/run/report/" + this.runId + "/debug";
|
||||
this.websocket = new WebSocket(uri);
|
||||
this.websocket.onmessage = this.onMessage;
|
||||
},
|
||||
onMessage(e) {
|
||||
if (e.data) {
|
||||
let data = JSON.parse(e.data);
|
||||
this.websocket.close();
|
||||
this.$emit('runRefresh', data);
|
||||
}
|
||||
},
|
||||
sort(stepArray) {
|
||||
if (stepArray) {
|
||||
for (let i in stepArray) {
|
||||
if (!stepArray[i].clazzName) {
|
||||
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
|
||||
}
|
||||
if (stepArray[i].hashTree && stepArray[i].hashTree.length > 0) {
|
||||
this.sort(stepArray[i].hashTree);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
run() {
|
||||
let projectId = getCurrentProjectID();
|
||||
|
||||
let testPlan = new TestPlan();
|
||||
testPlan.clazzName = TYPE_TO_C.get(testPlan.type);
|
||||
let threadGroup = new ThreadGroup();
|
||||
threadGroup.clazzName = TYPE_TO_C.get(threadGroup.type);
|
||||
threadGroup.hashTree = [];
|
||||
testPlan.hashTree = [threadGroup];
|
||||
this.runData.forEach(item => {
|
||||
item.projectId = projectId;
|
||||
if (!item.clazzName) {
|
||||
item.clazzName = TYPE_TO_C.get(item.type);
|
||||
}
|
||||
threadGroup.hashTree.push(item);
|
||||
})
|
||||
this.sort(testPlan.hashTree);
|
||||
let reqObj = {id: this.reportId, testElement: testPlan, type: this.type, clazzName: this.clazzName ? this.clazzName : TYPE_TO_C.get(this.type), projectId: projectId, environmentMap: strMapToObj(this.envMap)};
|
||||
let url = "/custom/func/run";
|
||||
reqObj.reportId = this.reportId;
|
||||
this.$post(url, reqObj, res => {
|
||||
this.runId = res.data;
|
||||
this.initWebSocket();
|
||||
}, () => {
|
||||
this.$emit('errorRefresh', {});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -11,7 +11,7 @@ export function generateFuncFirstLine(funcLanguage, funcName, funcParams) {
|
|||
let funcFirstLine = "";
|
||||
switch (funcLanguage) {
|
||||
case "beanshell":
|
||||
funcFirstLine = "function " + funcName + "(" + funcParams + ") " + "{";
|
||||
funcFirstLine = "public static void " + funcName + "(" + funcParams + ") " + "{";
|
||||
break;
|
||||
case "python":
|
||||
break;
|
||||
|
@ -27,7 +27,7 @@ export function generateFuncFirstLine(funcLanguage, funcName, funcParams) {
|
|||
}
|
||||
|
||||
const regex = {
|
||||
beanshell: /^function\s.*\(.*\)\s\{/,
|
||||
beanshell: /^public static void\s.*\(.*\)\s\{/,
|
||||
python: /^function\s.*\(.*\)\s\{/,
|
||||
groovy: /^function\s.*\(.*\)\s\{/,
|
||||
nashornScript: /^function\s.*\(.*\)\s\{/,
|
||||
|
|
Loading…
Reference in New Issue