feat(接口自动化): 完成场景变量基础存储功能

This commit is contained in:
fit2-zhao 2021-01-08 15:54:45 +08:00
parent 7c3b718863
commit 30762dae9f
9 changed files with 213 additions and 456 deletions

View File

@ -133,7 +133,7 @@ public class ApiAutomationController {
}
@PostMapping("/file/download")
public ResponseEntity<byte[]> downloadJmx(@RequestBody FileOperationRequest fileOperationRequest) {
public ResponseEntity<byte[]> download(@RequestBody FileOperationRequest fileOperationRequest) {
byte[] bytes = apiAutomationService.loadFileAsBytes(fileOperationRequest);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))

View File

@ -234,7 +234,7 @@ public class ApiDefinitionService {
test.setResponse(JSONObject.toJSONString(request.getResponse()));
test.setEnvironmentId(request.getEnvironmentId());
test.setUserId(request.getUserId());
test.setTags(JSON.toJSONString(new HashSet<>(request.getTags())));
test.setTags(request.getTags());
apiDefinitionMapper.updateByPrimaryKeySelective(test);
return test;
@ -265,7 +265,7 @@ public class ApiDefinitionService {
test.setUserId(request.getUserId());
}
test.setDescription(request.getDescription());
test.setTags(JSON.toJSONString(new HashSet<>(request.getTags())));
test.setTags(request.getTags());
apiDefinitionMapper.insert(test);
return test;
}
@ -341,10 +341,11 @@ public class ApiDefinitionService {
/**
* 内部构建HashTree 定时任务发起的执行
*
* @param request
* @return
*/
public String run(RunDefinitionRequest request,ApiTestCaseWithBLOBs item) {
public String run(RunDefinitionRequest request, ApiTestCaseWithBLOBs item) {
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
HashTree jmeterHashTree = new ListedHashTree();
@ -361,12 +362,14 @@ public class ApiDefinitionService {
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {});
new TypeReference<LinkedList<MsTestElement>>() {
});
scenario.setHashTree(elements);
}
if (StringUtils.isNotEmpty(element.getString("variables"))) {
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
new TypeReference<LinkedList<KeyValue>>() {});
LinkedList<ScenarioVariable> variables = mapper.readValue(element.getString("variables"),
new TypeReference<LinkedList<ScenarioVariable>>() {
});
scenario.setVariables(variables);
}
group.setEnableCookieShare(scenario.isEnableCookieShare());
@ -571,9 +574,9 @@ public class ApiDefinitionService {
apiDefinitionMapper.deleteByExample(example);
}
private List<String> getAllApiIdsByFontedSelect(List<String> filter, String name, List<String> moduleIds, String projectId, List<String> unSelectIds) {
private List<String> getAllApiIdsByFontedSelect(Map<String, List<String>> filters, String name, List<String> moduleIds, String projectId, List<String> unSelectIds) {
ApiDefinitionRequest request = new ApiDefinitionRequest();
request.setFilters(filter);
request.setFilters(filters);
request.setName(name);
request.setModuleIds(moduleIds);
request.setProjectId(projectId);

View File

@ -6,7 +6,7 @@
<el-col>
<!--操作按钮-->
<div class="ms-opt-btn">
<el-button type="primary" size="small" @click="editScenario">{{$t('commons.save')}}</el-button>
<el-button type="primary" size="small" @click="editScenario(true)">{{$t('commons.save')}}</el-button>
</div>
</el-col>
</el-row>
@ -220,7 +220,7 @@
</el-drawer>
<!--场景公共参数-->
<ms-variable-list :currentScenario="currentScenario" @setVariables="setVariables" ref="scenarioParameters"/>
<ms-variable-list @setVariables="setVariables" ref="scenarioParameters"/>
<!--外部导入-->
<api-import ref="apiImport" :saved="false" @refresh="apiImport"/>
</div>
@ -456,6 +456,10 @@
},
setVariables(v) {
this.currentScenario.variables = v;
if (this.path.endsWith("/update")) {
//
this.editScenario();
}
},
showButton(...names) {
for (const name of names) {
@ -677,12 +681,17 @@
this.$error(this.$t('api_test.environment.select_environment'));
return;
}
this.$refs['currentScenario'].validate((valid) => {
if (valid) {
this.editScenario();
this.debugData = {
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
variables: this.currentScenario.variables, referenced: 'Created', enableCookieShare: this.enableCookieShare,
environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition
};
this.reportId = getUUID().substring(0, 8);
}
})
},
getEnvironments() {
if (this.projectId) {
@ -821,13 +830,15 @@
})
return bodyUploadFiles;
},
editScenario() {
editScenario(showMessage) {
this.$refs['currentScenario'].validate((valid) => {
if (valid) {
this.setParameter();
let bodyFiles = this.getBodyUploadFiles(this.currentScenario);
this.$fileUpload(this.path, null, bodyFiles, this.currentScenario, response => {
if (showMessage) {
this.$success(this.$t('commons.save_success'));
}
this.path = "/api/automation/update";
if (response.data) {
this.currentScenario.id = response.data.id;

View File

@ -1,81 +1,30 @@
<template>
<el-dialog append-to-body :close-on-click-modal="false" :title="$t('api_test.scenario.variables')"
:visible.sync="visible" class="environment-dialog" width="40%"
@close="close">
<el-form :model="form" label-position="right" label-width="80px" size="small" ref="form" :rules="rule">
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form">
<el-form-item :label="$t('api_test.variable_name')" prop="name">
<el-input v-model="form.name" :placeholder="$t('api_test.variable_name')"></el-input>
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="form.description"
v-model="editData.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
<el-form-item :label="$t('api_test.value')" prop="value">
<el-input v-model="form.value" :placeholder="$t('api_test.value')"></el-input>
<el-input v-model="editData.value" :placeholder="$t('api_test.value')"></el-input>
</el-form-item>
</el-form>
<template v-slot:footer>
<ms-dialog-footer
@cancel="close"
@confirm="saveParameters"/>
</template>
</el-dialog>
</template>
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
export default {
name: "MsEditConstant",
components: {
MsDialogFooter
components: {},
props: {
editData: {},
},
data() {
return {
visible: false,
form: {type: "CONSTANT"},
editFlag: false,
rule: {
name: [
{required: true, message: this.$t('api_test.variable_name'), trigger: 'blur'},
],
},
}
},
methods: {
open: function (v) {
this.visible = true;
if (v) {
this.form = v;
this.editFlag = true;
} else {
this.form = {};
this.editFlag = false;
}
this.form.type = "CONSTANT";
},
close() {
this.visible = false;
this.form = {};
},
saveParameters() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.visible = false;
if (!this.editFlag) {
this.$emit('addParameters', this.form);
}
}
});
}
}
}
</script>

View File

@ -1,89 +1,38 @@
<template>
<el-dialog append-to-body :close-on-click-modal="false" title="计数器编辑"
:visible.sync="visible" class="environment-dialog" width="610px"
@close="close">
<el-form :model="form" label-position="right" label-width="80px" size="small" ref="form" :rules="rule">
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form2">
<el-form-item :label="$t('api_test.variable_name')" prop="name">
<el-input v-model="form.name" :placeholder="$t('api_test.variable_name')"></el-input>
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="form.description"
v-model="editData.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
<el-form-item label="开始" prop="set">
<el-input-number size="small" v-model="form.startNumber" placeholder="0" :max="1000*10000000" :min="0"/>
<el-input-number size="small" v-model="editData.startNumber" placeholder="0" :max="1000*10000000" :min="0"/>
<span style="margin: 0px 10px 10px ">结束</span>
<el-input-number size="small" v-model="form.endNumber" placeholder="10" :max="1000*10000000" :min="0"/>
<el-input-number size="small" v-model="editData.endNumber" placeholder="10" :max="1000*10000000" :min="0"/>
<span style="margin: 0px 10px 10px ">增量</span>
<el-input-number size="small" v-model="form.increment" placeholder="1" :max="1000*10000000" :min="0"/>
<el-input-number size="small" v-model="editData.increment" placeholder="1" :max="1000*10000000" :min="0"/>
</el-form-item>
<el-form-item label="开始" prop="value">
<el-input v-model="form.value" placeholder="000产生至少3位数字。user_000输出形式为user_nnn"></el-input>
<el-input v-model="editData.value" placeholder="000产生至少3位数字。user_000输出形式为user_nnn"></el-input>
</el-form-item>
</el-form>
<template v-slot:footer>
<ms-dialog-footer
@cancel="close"
@confirm="saveParameters"/>
</template>
</el-dialog>
</template>
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
export default {
name: "MsEditCounter",
components: {
MsDialogFooter
components: {},
props: {
editData: {},
},
data() {
return {
visible: false,
form: {type: "COUNTER"},
editFlag: false,
rule: {
name: [
{required: true, message: this.$t('api_test.variable_name'), trigger: 'blur'},
],
},
}
},
methods: {
open: function (v) {
this.visible = true;
if (v) {
this.form = v;
this.editFlag = true;
} else {
this.form = {};
this.editFlag = false;
}
this.form.type = "COUNTER";
},
close() {
this.visible = false;
this.form = {};
},
saveParameters() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.visible = false;
if (!this.editFlag) {
this.$emit('addParameters', this.form);
}
}
});
}
}
}
</script>

View File

@ -1,15 +1,12 @@
<template>
<el-dialog append-to-body :close-on-click-modal="false" title="CSV编辑"
:visible.sync="visible" class="environment-dialog" width="600px"
@close="close">
<el-form :model="form" label-position="right" label-width="80px" size="small" ref="form" :rules="rule">
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form3">
<el-form-item :label="$t('api_test.variable_name')" prop="name">
<el-input v-model="form.name" :placeholder="$t('api_test.variable_name')"></el-input>
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="form.description"
v-model="editData.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
@ -21,7 +18,7 @@
<span>添加文件</span>
</el-col>
<el-col :span="20">
<ms-csv-file-upload :parameter="form"/>
<ms-csv-file-upload :parameter="editData"/>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
@ -29,7 +26,7 @@
<span>Encoding</span>
</el-col>
<el-col :span="20">
<el-input v-model="form.encoding" size="small"/>
<el-input v-model="editData.encoding" size="small"/>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
@ -37,7 +34,7 @@
<span>分隔符</span>
</el-col>
<el-col :span="20">
<el-input v-model="form.splits" size="small"/>
<el-input v-model="editData.splits" size="small"/>
</el-col>
</el-row>
@ -59,31 +56,24 @@
</el-tab-pane>
</el-tabs>
</el-form>
<template v-slot:footer>
<ms-dialog-footer
@cancel="close"
@confirm="saveParameters"/>
</template>
</el-dialog>
</template>
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import MsCsvFileUpload from "./CsvFileUpload";
export default {
name: "MsEditCsv",
components: {
MsDialogFooter,
MsCsvFileUpload
},
props: {
editData: {},
},
data() {
return {
activeName: "config",
visible: false,
loading: false,
form: {type: "CSV"},
editFlag: false,
previewData: [],
columns: [],
@ -95,21 +85,6 @@
}
},
methods: {
open: function (v) {
this.visible = true;
if (v) {
this.form = v;
this.editFlag = true;
} else {
this.form = {};
this.editFlag = false;
}
this.form.type = "CSV";
},
close() {
this.visible = false;
this.form = {};
},
complete(results) {
if (results.errors && results.errors.length > 0) {
this.$error(results.errors);
@ -119,44 +94,32 @@
this.columns = results.data[0];
this.previewData = results.data;
}
this.loading = false;
},
handleClick() {
let config = {complete: this.complete};
//
if (this.form.files.length > 0 && this.form.files[0].file) {
this.$papa.parse(this.form.files[0].file, config);
if (this.editData.files && this.editData.files.length > 0 && this.editData.files[0].file) {
this.loading = true;
this.$papa.parse(this.editData.files[0].file, config);
}
//
if (this.form.files.length > 0 && !this.form.files[0].file) {
let file = this.form.files[0];
let config = {
if (this.editData.files && this.editData.files.length > 0 && !this.editData.files[0].file) {
let file = this.editData.files[0];
let conf = {
url: "/api/automation/file/download",
method: 'post',
data: file,
responseType: 'blob'
responseType: 'blob',
};
this.result = this.$request(config).then(response => {
this.result = this.$request(conf).then(response => {
const content = response.data;
const blob = new Blob([content]);
console.log(blob)
console.log(content)
let data = new FormData();
data.append("file", blob, blob.name);
this.$papa.parse(data, config);
this.loading = true;
this.$papa.parse(blob, config);
});
}
},
saveParameters() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.visible = false;
if (!this.editFlag) {
this.$emit('addParameters', this.form);
}
}
});
}
}
}
</script>

View File

@ -1,81 +1,30 @@
<template>
<el-dialog append-to-body :close-on-click-modal="false" title="列表编辑"
:visible.sync="visible" class="environment-dialog" width="40%"
@close="close">
<el-form :model="form" label-position="right" label-width="80px" size="small" ref="form" :rules="rule">
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form4">
<el-form-item :label="$t('api_test.variable_name')" prop="name">
<el-input v-model="form.name" :placeholder="$t('api_test.variable_name')"></el-input>
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="form.description"
v-model="editData.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
<el-form-item :label="$t('api_test.value')" prop="value">
<el-input v-model="form.value" placeholder="列表数据用,分隔"></el-input>
<el-input v-model="editData.value" placeholder="列表数据用,分隔"></el-input>
</el-form-item>
</el-form>
<template v-slot:footer>
<ms-dialog-footer
@cancel="close"
@confirm="saveParameters"/>
</template>
</el-dialog>
</template>
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
export default {
name: "MsEditListValue",
components: {
MsDialogFooter
components: {},
props: {
editData: {},
},
data() {
return {
visible: false,
form: {type: "LIST"},
editFlag: false,
rule: {
name: [
{required: true, message: this.$t('api_test.variable_name'), trigger: 'blur'},
],
},
}
},
methods: {
open: function (v) {
this.visible = true;
if (v) {
this.form = v;
this.editFlag = true;
} else {
this.form = {};
this.editFlag = false;
}
this.form.type = "LIST";
},
close() {
this.visible = false;
this.form = {};
},
saveParameters() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.visible = false;
if (!this.editFlag) {
this.$emit('addParameters', this.form);
}
}
});
}
}
}
</script>

View File

@ -1,87 +1,37 @@
<template>
<el-dialog append-to-body :close-on-click-modal="false" title="随机数编辑"
:visible.sync="visible" class="environment-dialog" width="600px"
@close="close">
<el-form :model="form" label-position="right" label-width="80px" size="small" ref="form" :rules="rule">
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form5">
<el-form-item :label="$t('api_test.variable_name')" prop="name">
<el-input v-model="form.name" :placeholder="$t('api_test.variable_name')"></el-input>
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="form.description"
v-model="editData.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
<el-form-item label="最小值" prop="set">
<el-input-number size="small" v-model="form.minNumber" placeholder="0" :max="1000*10000000" :min="0"/>
<el-input-number size="small" v-model="editData.minNumber" placeholder="0" :max="1000*10000000" :min="0"/>
<span style="margin: 0px 10px 10px ">最大值</span>
<el-input-number size="small" v-model="form.maxNumber" placeholder="10" :max="1000*10000000" :min="0"/>
<el-input-number size="small" v-model="editData.maxNumber" placeholder="10" :max="1000*10000000" :min="0"/>
</el-form-item>
<el-form-item label="开始" prop="value">
<el-input v-model="form.value" placeholder="000产生至少3位数字。user_000输出形式为user_nnn"></el-input>
<el-input v-model="editData.value" placeholder="000产生至少3位数字。user_000输出形式为user_nnn"></el-input>
</el-form-item>
</el-form>
<template v-slot:footer>
<ms-dialog-footer
@cancel="close"
@confirm="saveParameters"/>
</template>
</el-dialog>
</template>
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
export default {
name: "MsEditRandom",
components: {
MsDialogFooter
components: {},
props: {
editData: {},
},
data() {
return {
visible: false,
form: {type: "RANDOM"},
editFlag: false,
rule: {
name: [
{required: true, message: this.$t('api_test.variable_name'), trigger: 'blur'},
],
},
}
},
methods: {
open: function (v) {
this.visible = true;
if (v) {
this.form = v;
this.editFlag = true;
} else {
this.form = {};
this.editFlag = false;
}
this.form.type = "RANDOM";
},
close() {
this.visible = false;
this.form = {};
},
saveParameters() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.visible = false;
if (!this.editFlag) {
this.$emit('addParameters', this.form);
}
}
});
}
}
}
</script>

View File

@ -1,10 +1,14 @@
<template>
<el-dialog :title="$t('api_test.scenario.variables')"
:visible.sync="visible" class="environment-dialog" width="60%"
:visible.sync="visible" class="environment-dialog" width="70%"
@close="close">
<div>
<el-row>
<el-col :span="12">
<div style="border:1px #DCDFE6 solid; min-height: 400px;border-radius: 4px ;width: 100% ;">
<el-table ref="table" border :data="variables" class="adjust-table" @select-all="select" @select="select"
v-loading="loading">
v-loading="loading" @row-click="edit">
<el-table-column type="selection" width="38"/>
<el-table-column prop="num" label="ID" sortable/>
<el-table-column prop="name" :label="$t('api_test.variable_name')" sortable show-overflow-tooltip/>
@ -14,15 +18,20 @@
</template>
</el-table-column>
<el-table-column prop="value" :label="$t('api_test.value')" show-overflow-tooltip/>
<el-table-column :label="$t('commons.operating')">
<template v-slot:default="{row}">
<el-button type="text" @click="edit(row)">{{ $t('commons.edit') }}</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-col>
<el-col :span="12">
<ms-edit-constant v-if="editData.type=='CONSTANT'" ref="parameters" :editData.sync="editData"/>
<ms-edit-counter v-if="editData.type=='COUNTER'" ref="counter" :editData.sync="editData"/>
<ms-edit-random v-if="editData.type=='RANDOM'" ref="random" :editData.sync="editData"/>
<ms-edit-list-value v-if="editData.type=='LIST'" ref="listValue" :editData="editData"/>
<ms-edit-csv v-if="editData.type=='CSV'" ref="csv" :editData.sync="editData"/>
</el-col>
</el-row>
</div>
<template v-slot:footer>
<div style="margin:20px">
@ -41,11 +50,6 @@
</div>
</template>
<ms-edit-constant ref="parameters" @addParameters="addParameters"/>
<ms-edit-counter ref="counter" @addParameters="addParameters"/>
<ms-edit-random ref="random" @addParameters="addParameters"/>
<ms-edit-list-value ref="listValue" @addParameters="addParameters"/>
<ms-edit-csv ref="csv" @addParameters="addParameters"/>
</el-dialog>
</template>
@ -87,48 +91,19 @@
selection: [],
loading: false,
currentPage: 1,
editData: {},
pageSize: 10,
total: 0,
}
},
methods: {
handleClick(command) {
switch (command) {
case "CONSTANT":
this.$refs.parameters.open();
break;
case "LIST":
this.$refs.listValue.open();
break;
case "CSV":
this.$refs.csv.open();
break;
case "COUNTER":
this.$refs.counter.open();
break;
case "RANDOM":
this.$refs.random.open();
break;
}
this.editData = {};
this.editData.type = command;
this.addParameters(this.editData);
},
edit(row) {
switch (row.type) {
case "CONSTANT":
this.$refs.parameters.open(row);
break;
case "LIST":
this.$refs.listValue.open(row);
break;
case "CSV":
this.$refs.csv.open(row);
break;
case "COUNTER":
this.$refs.counter.open(row);
break;
case "RANDOM":
this.$refs.random.open(row);
break;
}
this.editData = row;
},
addParameters(v) {
v.id = getUUID();
@ -148,9 +123,17 @@
open: function (variables) {
this.variables = variables;
this.visible = true;
this.editData = {type: "CONSTANT"};
this.addParameters(this.editData);
},
close() {
this.visible = false;
this.variables.forEach(item => {
if (item.name === undefined || item.name === "") {
const index = this.variables.findIndex(d => d.id === item.id);
this.variables.splice(index, 1);
}
})
this.$emit('setVariables', this.variables);
},
deleteVariable() {