Merge branch 'v1.6'
This commit is contained in:
commit
f3dc01d3a9
|
@ -5,9 +5,9 @@ pipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
options { quietPeriod(600) }
|
options { quietPeriod(600) }
|
||||||
parameters {
|
environment {
|
||||||
string(name: 'IMAGE_NAME', defaultValue: 'metersphere', description: '构建后的 Docker 镜像名称')
|
IMAGE_NAME = 'metersphere'
|
||||||
string(name: 'IMAGE_PREFIX', defaultValue: 'registry.cn-qingdao.aliyuncs.com/metersphere', description: '构建后的 Docker 镜像带仓库名的前缀')
|
IMAGE_PREFIX = 'registry.cn-qingdao.aliyuncs.com/metersphere'
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage('Build/Test') {
|
stage('Build/Test') {
|
||||||
|
|
|
@ -324,8 +324,11 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
if (responseAssertionResult.isPass()) {
|
if (responseAssertionResult.isPass()) {
|
||||||
requestResult.addPassAssertions();
|
requestResult.addPassAssertions();
|
||||||
}
|
}
|
||||||
|
//xpath 提取错误会添加断言错误
|
||||||
|
if (!responseAssertionResult.getMessage().contains("The required item type of the first operand of")) {
|
||||||
responseResult.getAssertions().add(responseAssertionResult);
|
responseResult.getAssertions().add(responseAssertionResult);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
responseResult.setConsole(getConsole());
|
responseResult.setConsole(getConsole());
|
||||||
|
|
||||||
return requestResult;
|
return requestResult;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere.api.jmeter;
|
package io.metersphere.api.jmeter;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
|
import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
|
||||||
import org.apache.jmeter.extractor.JSR223PostProcessor;
|
import org.apache.jmeter.extractor.JSR223PostProcessor;
|
||||||
import org.apache.jmeter.extractor.RegexExtractor;
|
import org.apache.jmeter.extractor.RegexExtractor;
|
||||||
|
@ -32,10 +33,27 @@ public class JMeterVars {
|
||||||
*/
|
*/
|
||||||
public static void addVars(Integer testId, JMeterVariables vars, String extract) {
|
public static void addVars(Integer testId, JMeterVariables vars, String extract) {
|
||||||
JMeterVariables vs = new JMeterVariables();
|
JMeterVariables vs = new JMeterVariables();
|
||||||
|
|
||||||
if (!StringUtils.isEmpty(extract) && vars != null) {
|
if (!StringUtils.isEmpty(extract) && vars != null) {
|
||||||
List<String> extracts = Arrays.asList(extract.split(";"));
|
List<String> extracts = Arrays.asList(extract.split(";"));
|
||||||
Optional.ofNullable(extracts).orElse(new ArrayList<>()).forEach(item -> {
|
Optional.ofNullable(extracts).orElse(new ArrayList<>()).forEach(item -> {
|
||||||
|
|
||||||
|
String nrKey = item + "_matchNr";
|
||||||
|
Object nr = vars.get(nrKey);
|
||||||
|
if (nr != null) {
|
||||||
|
int nrv = 0;
|
||||||
|
try {
|
||||||
|
nrv = Integer.valueOf(String.valueOf(nr));
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
if (nrv > 0) {
|
||||||
|
List<Object> data = new ArrayList<>();
|
||||||
|
for (int i = 1; i < nrv + 1; i++) {
|
||||||
|
data.add(vars.get(item + "_" + i));
|
||||||
|
}
|
||||||
|
String array = JSON.toJSONString(data);
|
||||||
|
vars.put(item, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
vs.put(item, vars.get(item) == null ? "" : vars.get(item));
|
vs.put(item, vars.get(item) == null ? "" : vars.get(item));
|
||||||
});
|
});
|
||||||
vs.remove("TESTSTART.MS"); // 标示变量移除
|
vs.remove("TESTSTART.MS"); // 标示变量移除
|
||||||
|
|
|
@ -97,8 +97,10 @@ public class Swagger2Parser extends ApiImportAbstractParser {
|
||||||
String name = "";
|
String name = "";
|
||||||
if (StringUtils.isNotBlank(operation.getSummary())) {
|
if (StringUtils.isNotBlank(operation.getSummary())) {
|
||||||
name = operation.getSummary();
|
name = operation.getSummary();
|
||||||
} else {
|
} else if (StringUtils.isNotBlank(operation.getOperationId())) {
|
||||||
name = operation.getOperationId();
|
name = operation.getOperationId();
|
||||||
|
} else {
|
||||||
|
name = path;
|
||||||
}
|
}
|
||||||
return buildApiDefinition(id, name, path, method);
|
return buildApiDefinition(id, name, path, method);
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,8 +129,10 @@ public class Swagger3Parser extends ApiImportAbstractParser {
|
||||||
String name = "";
|
String name = "";
|
||||||
if (StringUtils.isNotBlank(operation.getSummary())) {
|
if (StringUtils.isNotBlank(operation.getSummary())) {
|
||||||
name = operation.getSummary();
|
name = operation.getSummary();
|
||||||
} else {
|
} else if (StringUtils.isNotBlank(operation.getOperationId())) {
|
||||||
name = operation.getOperationId();
|
name = operation.getOperationId();
|
||||||
|
} else {
|
||||||
|
name = path;
|
||||||
}
|
}
|
||||||
return buildApiDefinition(id, name, path, method);
|
return buildApiDefinition(id, name, path, method);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import io.metersphere.track.service.TestPlanApiCaseService;
|
||||||
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;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -60,6 +61,9 @@ public class ApiDefinitionExecResultService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteByResourceIds(List<String> ids) {
|
public void deleteByResourceIds(List<String> ids) {
|
||||||
|
if (CollectionUtils.isEmpty(ids)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ApiDefinitionExecResultExample example = new ApiDefinitionExecResultExample();
|
ApiDefinitionExecResultExample example = new ApiDefinitionExecResultExample();
|
||||||
example.createCriteria().andResourceIdIn(ids);
|
example.createCriteria().andResourceIdIn(ids);
|
||||||
apiDefinitionExecResultMapper.deleteByExample(example);
|
apiDefinitionExecResultMapper.deleteByExample(example);
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class JmeterFileService {
|
||||||
if (!CollectionUtils.isEmpty(testData)) {
|
if (!CollectionUtils.isEmpty(testData)) {
|
||||||
for (String k : testData.keySet()) {
|
for (String k : testData.keySet()) {
|
||||||
String v = testData.get(k);
|
String v = testData.get(k);
|
||||||
files.put("k", v.getBytes(StandardCharsets.UTF_8));
|
files.put(k, v.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ public class JmeterFileService {
|
||||||
if (!CollectionUtils.isEmpty(jarFiles)) {
|
if (!CollectionUtils.isEmpty(jarFiles)) {
|
||||||
for (String k : jarFiles.keySet()) {
|
for (String k : jarFiles.keySet()) {
|
||||||
byte[] v = jarFiles.get(k);
|
byte[] v = jarFiles.get(k);
|
||||||
files.put("k", v);
|
files.put(k, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
ref="codeEdit"/>
|
ref="codeEdit"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4" class="script-index">
|
<el-col :span="4" class="script-index">
|
||||||
<ms-dropdown :default-command="jsr223ProcessorData.language" :commands="languages" @command="languageChange"/>
|
<ms-dropdown :default-command="jsr223ProcessorData.scriptLanguage" :commands="languages" @command="languageChange"/>
|
||||||
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
|
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
|
||||||
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
|
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
|
||||||
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link>
|
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link>
|
||||||
|
@ -135,7 +135,7 @@
|
||||||
this.jsr223ProcessorData.script = "";
|
this.jsr223ProcessorData.script = "";
|
||||||
}
|
}
|
||||||
this.jsr223ProcessorData.script += template.value;
|
this.jsr223ProcessorData.script += template.value;
|
||||||
if (this.jsr223ProcessorData.language === 'beanshell') {
|
if (this.jsr223ProcessorData.scriptLanguage === 'beanshell') {
|
||||||
this.jsr223ProcessorData.script += ';';
|
this.jsr223ProcessorData.script += ';';
|
||||||
}
|
}
|
||||||
this.reload();
|
this.reload();
|
||||||
|
@ -151,7 +151,7 @@
|
||||||
this.$nextTick(() => (this.isCodeEditAlive = true));
|
this.$nextTick(() => (this.isCodeEditAlive = true));
|
||||||
},
|
},
|
||||||
languageChange(language) {
|
languageChange(language) {
|
||||||
this.jsr223ProcessorData.language = language;
|
this.jsr223ProcessorData.scriptLanguage = language;
|
||||||
},
|
},
|
||||||
changeActive() {
|
changeActive() {
|
||||||
this.jsr223ProcessorData.active = !this.jsr223ProcessorData.active;
|
this.jsr223ProcessorData.active = !this.jsr223ProcessorData.active;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
<el-input placeholder="搜索" @blur="initTable" class="search-input" size="small" @keyup.enter.native="initTable" v-model="condition.name"/>
|
<el-input placeholder="搜索" @blur="initTable" class="search-input" size="small" @keyup.enter.native="initTable" v-model="condition.name"/>
|
||||||
|
|
||||||
|
|
||||||
<el-table v-loading="result.loading"
|
<el-table v-loading="result.loading"
|
||||||
border
|
border
|
||||||
:data="tableData" row-key="id" class="test-content adjust-table"
|
:data="tableData" row-key="id" class="test-content adjust-table"
|
||||||
|
@ -253,8 +254,8 @@
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
float: right;
|
float: right;
|
||||||
width: 300px;
|
width: 30%;
|
||||||
/*margin-bottom: 20px;*/
|
margin-bottom: 20px;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default class JSR223PostProcessor extends PostProcessor {
|
||||||
constructor(options = DEFAULT_OPTIONS) {
|
constructor(options = DEFAULT_OPTIONS) {
|
||||||
super(options);
|
super(options);
|
||||||
this.type = "JSR223PostProcessor";
|
this.type = "JSR223PostProcessor";
|
||||||
this.scriptLanguage = "java";
|
this.scriptLanguage = "beanshell";
|
||||||
this.parameters = [];
|
this.parameters = [];
|
||||||
this.filename = undefined;
|
this.filename = undefined;
|
||||||
this.cacheKey = true;
|
this.cacheKey = true;
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default class JSR223PreProcessor extends PostProcessor {
|
||||||
constructor(options = DEFAULT_OPTIONS) {
|
constructor(options = DEFAULT_OPTIONS) {
|
||||||
super(options);
|
super(options);
|
||||||
this.type = "JSR223PreProcessor";
|
this.type = "JSR223PreProcessor";
|
||||||
this.scriptLanguage = "java";
|
this.scriptLanguage = "beanshell";
|
||||||
this.parameters = [];
|
this.parameters = [];
|
||||||
this.filename = undefined;
|
this.filename = undefined;
|
||||||
this.cacheKey = undefined;
|
this.cacheKey = undefined;
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="casePassingRate"
|
prop="casePassingRate"
|
||||||
|
:width="100"
|
||||||
:label="$t('api_test.definition.api_case_passing_rate')"
|
:label="$t('api_test.definition.api_case_passing_rate')"
|
||||||
show-overflow-tooltip/>
|
show-overflow-tooltip/>
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ export default {
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.protocol-select {
|
.protocol-select {
|
||||||
width: 95px;
|
width: 92px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
ref="codeEdit"/>
|
ref="codeEdit"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4" class="script-index">
|
<el-col :span="4" class="script-index">
|
||||||
<ms-dropdown :default-command="jsr223ProcessorData.language" :commands="languages" @command="languageChange"/>
|
<ms-dropdown :default-command="jsr223ProcessorData.scriptLanguage" :commands="languages" @command="languageChange"/>
|
||||||
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
|
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
|
||||||
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
|
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
|
||||||
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link>
|
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link>
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
this.jsr223ProcessorData.script = "";
|
this.jsr223ProcessorData.script = "";
|
||||||
}
|
}
|
||||||
this.jsr223ProcessorData.script += template.value;
|
this.jsr223ProcessorData.script += template.value;
|
||||||
if (this.jsr223ProcessorData.language === 'beanshell') {
|
if (this.jsr223ProcessorData.scriptLanguage === 'beanshell') {
|
||||||
this.jsr223ProcessorData.script += ';';
|
this.jsr223ProcessorData.script += ';';
|
||||||
}
|
}
|
||||||
this.reload();
|
this.reload();
|
||||||
|
@ -156,7 +156,7 @@
|
||||||
this.$nextTick(() => (this.isCodeEditAlive = true));
|
this.$nextTick(() => (this.isCodeEditAlive = true));
|
||||||
},
|
},
|
||||||
languageChange(language) {
|
languageChange(language) {
|
||||||
this.jsr223ProcessorData.language = language;
|
this.jsr223ProcessorData.scriptLanguage = language;
|
||||||
},
|
},
|
||||||
changeActive() {
|
changeActive() {
|
||||||
this.active = !this.active;
|
this.active = !this.active;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item command="ref">{{ $t('api_test.automation.view_ref') }}</el-dropdown-item>
|
<el-dropdown-item command="ref">{{ $t('api_test.automation.view_ref') }}</el-dropdown-item>
|
||||||
<el-dropdown-item :disabled="isCaseEdit" command="add_plan">{{ $t('api_test.automation.batch_add_plan') }}</el-dropdown-item>
|
<!--<el-dropdown-item :disabled="isCaseEdit" command="add_plan">{{ $t('api_test.automation.batch_add_plan') }}</el-dropdown-item>-->
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
<ms-reference-view ref="viewRef"/>
|
<ms-reference-view ref="viewRef"/>
|
||||||
<!--测试计划-->
|
<!--测试计划-->
|
||||||
|
|
|
@ -842,8 +842,7 @@ export class JSR223Processor extends BaseConfig {
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.type = "JSR223Processor";
|
this.type = "JSR223Processor";
|
||||||
this.script = undefined;
|
this.script = undefined;
|
||||||
this.language = "beanshell";
|
this.scriptLanguage = "beanshell";
|
||||||
this.scriptLanguage = "java";
|
|
||||||
this.enable = true;
|
this.enable = true;
|
||||||
this.hashTree = [];
|
this.hashTree = [];
|
||||||
this.set(options);
|
this.set(options);
|
||||||
|
|
|
@ -118,7 +118,21 @@ export default {
|
||||||
},
|
},
|
||||||
copyRequest(index) {
|
copyRequest(index) {
|
||||||
let request = this.scenario.requests[index];
|
let request = this.scenario.requests[index];
|
||||||
this.scenario.requests.push(new RequestFactory(request));
|
let item = new RequestFactory(request);
|
||||||
|
if (item.body && item.body.kvs) {
|
||||||
|
item.body.kvs.forEach(kv => {
|
||||||
|
let files = [];
|
||||||
|
if (kv.files) {
|
||||||
|
kv.files.forEach(file => {
|
||||||
|
let fileCopy = {};
|
||||||
|
Object.assign(fileCopy, file);
|
||||||
|
files.push(fileCopy);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
kv.files = files;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.scenario.requests.push(item);
|
||||||
},
|
},
|
||||||
disableRequest(index) {
|
disableRequest(index) {
|
||||||
this.scenario.requests[index].enable = false;
|
this.scenario.requests[index].enable = false;
|
||||||
|
|
|
@ -59,7 +59,11 @@
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.el-dialog {
|
.el-dialog {
|
||||||
min-height: 700px;
|
min-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-aside {
|
||||||
|
max-height: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-dialog >>> .el-dialog__body {
|
.el-dialog >>> .el-dialog__body {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ckeditor v-if="!isReportView" :editor="editor" v-model="preview.content" :config="editorConfig"></ckeditor>
|
<ckeditor v-if="!isReportView" :editor="editor" v-model="preview.content" :config="editorConfig"></ckeditor>
|
||||||
<div v-if="isReportView" v-html="preview.content"></div>
|
<div class="rich-text-content" v-if="isReportView" v-html="preview.content"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</common-component>
|
</common-component>
|
||||||
|
@ -53,4 +53,11 @@
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
|
.rich-text-content >>> .table td {
|
||||||
|
border: solid 1px #e6e6e6;
|
||||||
|
min-width: 2em;
|
||||||
|
padding: .4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -142,9 +142,9 @@ html,body {
|
||||||
border: 1px solid #DCDFE6;
|
border: 1px solid #DCDFE6;
|
||||||
border-radius:5px;
|
border-radius:5px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin-top: 5px;
|
margin-top: 10px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-top: 25px;
|
/*margin-top: 25px;*/
|
||||||
width: 50px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,8 +164,8 @@ html,body {
|
||||||
.ms-select-all .el-icon-arrow-down {
|
.ms-select-all .el-icon-arrow-down {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
top: -3px;
|
top: -7px;
|
||||||
left: -40px;
|
left: -38px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
}
|
}
|
||||||
/* 表格全选样式 --> */
|
/* 表格全选样式 --> */
|
||||||
|
|
Loading…
Reference in New Issue