feat(接口定义): TCP,SQL,DUBBO 协议基本录入完成

This commit is contained in:
fit2-zhao 2020-11-25 15:31:06 +08:00
parent cbc9c42122
commit 8db0b4349a
27 changed files with 2074 additions and 342 deletions

View File

@ -10,7 +10,10 @@ import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager;
import io.metersphere.api.dto.definition.request.extract.MsExtract; import io.metersphere.api.dto.definition.request.extract.MsExtract;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor; import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor; import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import lombok.Data; import lombok.Data;
import org.apache.jmeter.protocol.http.control.AuthManager; import org.apache.jmeter.protocol.http.control.AuthManager;
@ -33,9 +36,14 @@ import java.util.List;
@JsonSubTypes.Type(value = MsAuthManager.class, name = "AuthManager"), @JsonSubTypes.Type(value = MsAuthManager.class, name = "AuthManager"),
@JsonSubTypes.Type(value = MsAssertions.class, name = "Assertions"), @JsonSubTypes.Type(value = MsAssertions.class, name = "Assertions"),
@JsonSubTypes.Type(value = MsExtract.class, name = "Extract"), @JsonSubTypes.Type(value = MsExtract.class, name = "Extract"),
@JsonSubTypes.Type(value = MsTCPSampler.class, name = "TCPSampler"),
@JsonSubTypes.Type(value = MsDubboSampler.class, name = "DubboSampler"),
@JsonSubTypes.Type(value = MsJDBCSampler.class, name = "JDBCSampler"),
}) })
@JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223PostProcessor.class, MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class, MsExtract.class}, typeKey = "type") @JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223PostProcessor.class,
MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class,
MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class}, typeKey = "type")
@Data @Data
public abstract class MsTestElement { public abstract class MsTestElement {
private String type; private String type;

View File

@ -0,0 +1,143 @@
package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
import io.github.ningyu.jmeter.plugin.dubbo.sample.MethodArgument;
import io.github.ningyu.jmeter.plugin.util.Constants;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConfigCenter;
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConsumerAndService;
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsRegistryCenter;
import io.metersphere.api.dto.scenario.KeyValue;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import java.util.List;
import java.util.stream.Collectors;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "DubboSampler")
public class MsDubboSampler extends MsTestElement {
// type 必须放最前面以便能够转换正确的类
private String type = "DubboSampler";
@JSONField(ordinal = 52)
private String protocol;
@JsonProperty(value = "interface")
@JSONField(ordinal = 53, name = "interface")
private String _interface;
@JSONField(ordinal = 54)
private String method;
@JSONField(ordinal = 55)
private MsConfigCenter configCenter;
@JSONField(ordinal = 56)
private MsRegistryCenter registryCenter;
@JSONField(ordinal = 57)
private MsConsumerAndService consumerAndService;
@JSONField(ordinal = 58)
private List<KeyValue> args;
@JSONField(ordinal = 59)
private List<KeyValue> attachmentArgs;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
final HashTree testPlanTree = new ListedHashTree();
testPlanTree.add(dubboConfig());
tree.set(dubboSample(), testPlanTree);
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(testPlanTree, el.getHashTree());
});
}
}
private DubboSample dubboSample() {
DubboSample sampler = new DubboSample();
sampler.setName(this.getName());
sampler.setProperty(TestElement.TEST_CLASS, DubboSample.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("DubboSampleGui"));
sampler.addTestElement(configCenter(this.getConfigCenter()));
sampler.addTestElement(registryCenter(this.getRegistryCenter()));
sampler.addTestElement(consumerAndService(this.getConsumerAndService()));
Constants.setRpcProtocol(this.getProtocol(), sampler);
Constants.setInterfaceName(this.get_interface(), sampler);
Constants.setMethod(this.getMethod(), sampler);
List<MethodArgument> methodArgs = this.getArgs().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable)
.map(keyValue -> new MethodArgument(keyValue.getName(), keyValue.getValue())).collect(Collectors.toList());
Constants.setMethodArgs(methodArgs, sampler);
List<MethodArgument> attachmentArgs = this.getAttachmentArgs().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable)
.map(keyValue -> new MethodArgument(keyValue.getName(), keyValue.getValue())).collect(Collectors.toList());
Constants.setAttachmentArgs(attachmentArgs, sampler);
return sampler;
}
private ConfigTestElement dubboConfig() {
ConfigTestElement configTestElement = new ConfigTestElement();
configTestElement.setEnabled(true);
configTestElement.setName(this.getName());
configTestElement.setProperty(TestElement.TEST_CLASS, ConfigTestElement.class.getName());
configTestElement.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("DubboDefaultConfigGui"));
configTestElement.addConfigElement(configCenter(this.getConfigCenter()));
configTestElement.addConfigElement(registryCenter(this.getRegistryCenter()));
configTestElement.addConfigElement(consumerAndService(this.getConsumerAndService()));
return configTestElement;
}
private ConfigTestElement configCenter(MsConfigCenter configCenter) {
ConfigTestElement configTestElement = new ConfigTestElement();
if (configCenter != null) {
Constants.setConfigCenterProtocol(configCenter.getProtocol(), configTestElement);
Constants.setConfigCenterGroup(configCenter.getGroup(), configTestElement);
Constants.setConfigCenterNamespace(configCenter.getNamespace(), configTestElement);
Constants.setConfigCenterUserName(configCenter.getUsername(), configTestElement);
Constants.setConfigCenterPassword(configCenter.getPassword(), configTestElement);
Constants.setConfigCenterAddress(configCenter.getAddress(), configTestElement);
Constants.setConfigCenterTimeout(configCenter.getTimeout(), configTestElement);
}
return configTestElement;
}
private ConfigTestElement registryCenter(MsRegistryCenter registryCenter) {
ConfigTestElement configTestElement = new ConfigTestElement();
if (registryCenter != null) {
Constants.setRegistryProtocol(registryCenter.getProtocol(), configTestElement);
Constants.setRegistryGroup(registryCenter.getGroup(), configTestElement);
Constants.setRegistryUserName(registryCenter.getUsername(), configTestElement);
Constants.setRegistryPassword(registryCenter.getPassword(), configTestElement);
Constants.setRegistryTimeout(registryCenter.getTimeout(), configTestElement);
Constants.setAddress(registryCenter.getAddress(), configTestElement);
}
return configTestElement;
}
private ConfigTestElement consumerAndService(MsConsumerAndService consumerAndService) {
ConfigTestElement configTestElement = new ConfigTestElement();
if (consumerAndService != null) {
Constants.setTimeout(consumerAndService.getTimeout(), configTestElement);
Constants.setVersion(consumerAndService.getVersion(), configTestElement);
Constants.setGroup(consumerAndService.getGroup(), configTestElement);
Constants.setConnections(consumerAndService.getConnections(), configTestElement);
Constants.setLoadbalance(consumerAndService.getLoadBalance(), configTestElement);
Constants.setAsync(consumerAndService.getAsync(), configTestElement);
Constants.setCluster(consumerAndService.getCluster(), configTestElement);
}
return configTestElement;
}
}

View File

@ -0,0 +1,103 @@
package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.DatabaseConfig;
import io.metersphere.api.dto.scenario.KeyValue;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.jdbc.config.DataSourceElement;
import org.apache.jmeter.protocol.jdbc.sampler.JDBCSampler;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "JDBCSampler")
public class MsJDBCSampler extends MsTestElement {
// type 必须放最前面以便能够转换正确的类
private String type = "JDBCSampler";
@JSONField(ordinal = 10)
private DatabaseConfig dataSource;
@JSONField(ordinal = 11)
private String query;
@JSONField(ordinal = 12)
private long queryTimeout;
@JSONField(ordinal = 13)
private String resultVariable;
@JSONField(ordinal = 14)
private String variableNames;
@JSONField(ordinal = 15)
private List<KeyValue> variables;
@JSONField(ordinal = 16)
private String environmentId;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
final HashTree samplerHashTree = new ListedHashTree();
samplerHashTree.add(jdbcDataSource());
samplerHashTree.add(arguments(this.getName() + " Variables", this.getVariables()));
tree.set(jdbcSampler(), samplerHashTree);
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(samplerHashTree, el.getHashTree());
});
}
}
private Arguments arguments(String name, List<KeyValue> variables) {
Arguments arguments = new Arguments();
arguments.setEnabled(true);
arguments.setName(name);
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
variables.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
);
return arguments;
}
private JDBCSampler jdbcSampler() {
JDBCSampler sampler = new JDBCSampler();
sampler.setName(this.getName());
sampler.setProperty(TestElement.TEST_CLASS, JDBCSampler.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
// request.getDataSource() 是ID需要转换为Name
sampler.setDataSource(this.dataSource.getName());
sampler.setQuery(this.getQuery());
sampler.setQueryTimeout(String.valueOf(this.getQueryTimeout()));
sampler.setResultVariable(this.getResultVariable());
sampler.setVariableNames(this.getVariableNames());
sampler.setResultSetHandler("Store as String");
sampler.setQueryType("Callable Statement");
return sampler;
}
private DataSourceElement jdbcDataSource() {
DataSourceElement dataSourceElement = new DataSourceElement();
dataSourceElement.setEnabled(true);
dataSourceElement.setName(this.getName() + " JDBCDataSource");
dataSourceElement.setProperty(TestElement.TEST_CLASS, DataSourceElement.class.getName());
dataSourceElement.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
dataSourceElement.setAutocommit(true);
dataSourceElement.setKeepAlive(true);
dataSourceElement.setPreinit(true);
dataSourceElement.setDataSource(dataSource.getName());
dataSourceElement.setDbUrl(dataSource.getDbUrl());
dataSourceElement.setDriver(dataSource.getDriver());
dataSourceElement.setUsername(dataSource.getUsername());
dataSourceElement.setPassword(dataSource.getPassword());
dataSourceElement.setPoolMax(String.valueOf(dataSource.getPoolMax()));
dataSourceElement.setTimeout(String.valueOf(dataSource.getTimeout()));
dataSourceElement.setConnectionAge("5000");
dataSourceElement.setTrimInterval("60000");
dataSourceElement.setTransactionIsolation("DEFAULT");
return dataSourceElement;
}
}

View File

@ -0,0 +1,104 @@
package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.protocol.tcp.sampler.TCPSampler;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "TCPSampler")
public class MsTCPSampler extends MsTestElement {
@JSONField(ordinal = 10)
private String type = "TCPSampler";
@JSONField(ordinal = 11)
private String classname = "";
@JSONField(ordinal = 12)
private String server = "";
@JSONField(ordinal = 13)
private String port = "";
@JSONField(ordinal = 14)
private String ctimeout = "";
@JSONField(ordinal = 15)
private String timeout = "";
@JSONField(ordinal = 16)
private boolean reUseConnection = true;
@JSONField(ordinal = 17)
private boolean nodelay;
@JSONField(ordinal = 18)
private boolean closeConnection;
@JSONField(ordinal = 19)
private String soLinger = "";
@JSONField(ordinal = 20)
private String eolByte = "";
@JSONField(ordinal = 21)
private String username = "";
@JSONField(ordinal = 22)
private String password = "";
@JSONField(ordinal = 23)
private String request;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
final HashTree samplerHashTree = new ListedHashTree();
samplerHashTree.add(tcpConfig());
tree.set(tcpSampler(), samplerHashTree);
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(samplerHashTree, el.getHashTree());
});
}
}
private TCPSampler tcpSampler() {
TCPSampler tcpSampler = new TCPSampler();
tcpSampler.setName(this.getName());
tcpSampler.setProperty(TestElement.TEST_CLASS, TCPSampler.class.getName());
tcpSampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TCPSamplerGui"));
tcpSampler.setClassname(this.getClassname());
tcpSampler.setServer(this.getServer());
tcpSampler.setPort(this.getPort());
tcpSampler.setConnectTimeout(this.getCtimeout());
tcpSampler.setProperty(TCPSampler.RE_USE_CONNECTION, this.isReUseConnection());
tcpSampler.setProperty(TCPSampler.NODELAY, this.isNodelay());
tcpSampler.setCloseConnection(String.valueOf(this.isCloseConnection()));
tcpSampler.setSoLinger(this.getSoLinger());
tcpSampler.setEolByte(this.getEolByte());
tcpSampler.setRequestData(this.getRequest());
tcpSampler.setProperty(ConfigTestElement.USERNAME, this.getUsername());
tcpSampler.setProperty(ConfigTestElement.PASSWORD, this.getPassword());
return tcpSampler;
}
private ConfigTestElement tcpConfig() {
ConfigTestElement configTestElement = new ConfigTestElement();
configTestElement.setEnabled(true);
configTestElement.setName(this.getName());
configTestElement.setProperty(TestElement.TEST_CLASS, ConfigTestElement.class.getName());
configTestElement.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TCPConfigGui"));
configTestElement.setProperty(TCPSampler.CLASSNAME, this.getClassname());
configTestElement.setProperty(TCPSampler.SERVER, this.getServer());
configTestElement.setProperty(TCPSampler.PORT, this.getPort());
configTestElement.setProperty(TCPSampler.TIMEOUT_CONNECT, this.getCtimeout());
configTestElement.setProperty(TCPSampler.RE_USE_CONNECTION, this.isReUseConnection());
configTestElement.setProperty(TCPSampler.NODELAY, this.isNodelay());
configTestElement.setProperty(TCPSampler.CLOSE_CONNECTION, this.isCloseConnection());
configTestElement.setProperty(TCPSampler.SO_LINGER, this.getSoLinger());
configTestElement.setProperty(TCPSampler.EOL_BYTE, this.getEolByte());
configTestElement.setProperty(TCPSampler.SO_LINGER, this.getSoLinger());
configTestElement.setProperty(ConfigTestElement.USERNAME, this.getUsername());
configTestElement.setProperty(ConfigTestElement.PASSWORD, this.getPassword());
return configTestElement;
}
}

View File

@ -0,0 +1,14 @@
package io.metersphere.api.dto.definition.request.sampler.dubbo;
import lombok.Data;
@Data
public class MsConfigCenter {
private String protocol;
private String group;
private String namespace;
private String username;
private String address;
private String password;
private String timeout;
}

View File

@ -0,0 +1,15 @@
package io.metersphere.api.dto.definition.request.sampler.dubbo;
import lombok.Data;
@Data
public class MsConsumerAndService {
private String timeout;
private String version;
private String retries;
private String cluster;
private String group;
private String connections;
private String async;
private String loadBalance;
}

View File

@ -0,0 +1,13 @@
package io.metersphere.api.dto.definition.request.sampler.dubbo;
import lombok.Data;
@Data
public class MsRegistryCenter {
private String protocol;
private String group;
private String username;
private String address;
private String password;
private String timeout;
}

View File

@ -2,18 +2,28 @@
<div class="card-container"> <div class="card-container">
<!-- HTTP 请求参数 --> <!-- HTTP 请求参数 -->
<ms-add-complete-http-api @runTest="runTest" @saveApi="saveApi" :request="request" :headers="headers" :response="response" :basisData="currentApi" <ms-add-complete-http-api @runTest="runTest" @saveApi="saveApi" :request="request" :headers="headers" :response="response"
:moduleOptions="moduleOptions" :currentProject="currentProject" :basisData="currentApi" :moduleOptions="moduleOptions" :currentProject="currentProject" v-if="currentProtocol === 'HTTP'"/>
v-if="currentProtocol === 'HTTP'"/>
<!-- TCP --> <!-- TCP -->
<ms-api-tcp-request-form :request="request" :currentProject="currentProject" :basisData="currentApi" :moduleOptions="moduleOptions" :maintainerOptions="maintainerOptions" v-if="currentProtocol === 'TCP'"/> <ms-add-complete-tcp-api :request="request" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'TCP'"/>
<!--DUBBO-->
<ms-add-complete-dubbo-api :request="request" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'DUBBO'"/>
<!--SQL-->
<ms-add-complete-sql-api :request="request" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'SQL'"/>
</div> </div>
</template> </template>
<script> <script>
import MsAddCompleteHttpApi from "./complete/AddCompleteHttpApi"; import MsAddCompleteHttpApi from "./complete/AddCompleteHttpApi";
import MsApiTcpRequestForm from "./complete/ApiTcpRequestForm"; import MsAddCompleteTcpApi from "./complete/AddCompleteTcpApi";
import MsAddCompleteDubboApi from "./complete/AddCompleteDubboApi";
import MsAddCompleteSqlApi from "./complete/AddCompleteSqlApi";
import {ResponseFactory, Body} from "../model/ApiTestModel"; import {ResponseFactory, Body} from "../model/ApiTestModel";
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import {createComponent, Request} from "./jmeter/components"; import {createComponent, Request} from "./jmeter/components";
@ -23,7 +33,7 @@
export default { export default {
name: "ApiConfig", name: "ApiConfig",
components: {MsAddCompleteHttpApi, MsApiTcpRequestForm}, components: {MsAddCompleteHttpApi, MsAddCompleteTcpApi, MsAddCompleteDubboApi, MsAddCompleteSqlApi},
data() { data() {
return { return {
reqUrl: "", reqUrl: "",
@ -44,16 +54,16 @@
this.getMaintainerOptions(); this.getMaintainerOptions();
switch (this.currentProtocol) { switch (this.currentProtocol) {
case Request.TYPES.SQL: case Request.TYPES.SQL:
this.request = createComponent("SQL"); this.initSql();
break; break;
case Request.TYPES.DUBBO: case Request.TYPES.DUBBO:
this.request = createComponent("JDBCSampler"); this.initDubbo();
break; break;
case Request.TYPES.TCP: case Request.TYPES.TCP:
this.request = createComponent("TCPSampler"); this.initTcp();
break; break;
default: default:
this.createHttp(); this.initHttp();
break; break;
} }
if (this.currentApi.response != null && this.currentApi.response != 'null' && this.currentApi.response != undefined) { if (this.currentApi.response != null && this.currentApi.response != 'null' && this.currentApi.response != undefined) {
@ -84,8 +94,31 @@
this.maintainerOptions = response.data; this.maintainerOptions = response.data;
}); });
}, },
initSql() {
createHttp() { if (this.currentApi.request != undefined && this.currentApi.request != null) {
this.request = JSON.parse(this.currentApi.request);
this.currentApi.request = this.request;
} else {
this.request = createComponent("JDBCSampler");
}
},
initDubbo() {
if (this.currentApi.request != undefined && this.currentApi.request != null) {
this.request = JSON.parse(this.currentApi.request);
this.currentApi.request = this.request;
} else {
this.request = createComponent("DubboSampler");
}
},
initTcp() {
if (this.currentApi.request != undefined && this.currentApi.request != null) {
this.request = JSON.parse(this.currentApi.request);
this.currentApi.request = this.request;
} else {
this.request = createComponent("TCPSampler");
}
},
initHttp() {
if (this.currentApi.request != undefined && this.currentApi.request != null) { if (this.currentApi.request != undefined && this.currentApi.request != null) {
this.request = JSON.parse(this.currentApi.request); this.request = JSON.parse(this.currentApi.request);
this.currentApi.request = this.request; this.currentApi.request = this.request;
@ -108,8 +141,12 @@
}, },
setParameters(data) { setParameters(data) {
console.log(data)
data.projectId = this.currentProject.id; data.projectId = this.currentProject.id;
if (this.currentProtocol === 'HTTP') {
this.request.hashTree[0].headers = this.headers; this.request.hashTree[0].headers = this.headers;
}
this.request.name = this.currentProject.name;
data.request = this.request; data.request = this.request;
data.response = this.response; data.response = this.response;
}, },

View File

@ -28,8 +28,8 @@
</template> </template>
<script> <script>
import {KeyValue} from "../../model/ApiTestModel"; import {KeyValue} from "../model/ApiTestModel";
import MsApiVariableInput from "../ApiVariableInput"; import MsApiVariableInput from "./ApiVariableInput";
export default { export default {
name: "MsApiScenarioVariables", name: "MsApiScenarioVariables",

View File

@ -0,0 +1,79 @@
<template>
<!-- 操作按钮 -->
<div style="background-color: white;">
<el-row>
<el-col>
<!--操作按钮-->
<div style="float: right;margin-right: 20px;margin-top: 20px">
<el-button type="primary" size="small" @click="validateApi">{{$t('commons.save')}}</el-button>
<el-button type="primary" size="small" @click="runTest">{{$t('commons.test')}}</el-button>
</div>
</el-col>
</el-row>
<!-- 基础信息 -->
<p class="tip">{{$t('test_track.plan_view.base_info')}} </p>
<br/>
<el-row>
<el-col>
<ms-basis-api :moduleOptions="moduleOptions" :basisData="basisData" ref="basicForm" @callback="saveApi"/>
</el-col>
</el-row>
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
</div>
</template>
<script>
import MsBasisApi from "./BasisApi";
import MsBasisParameters from "../request/dubbo/BasisParameters";
export default {
name: "MsApiDubboRequestForm",
components: {
MsBasisApi, MsBasisParameters
},
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
default: false
}
},
methods: {
validateApi() {
this.basisData.method = this.request.protocol;
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {
this.$emit('saveApi', this.basisData);
},
runTest() {
}
},
computed: {}
}
</script>
<style scoped>
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 0px 20px 0px;
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<!-- 操作按钮 -->
<div style="background-color: white;">
<el-row>
<el-col>
<!--操作按钮-->
<div style="float: right;margin-right: 20px;margin-top: 20px">
<el-button type="primary" size="small" @click="validateApi">{{$t('commons.save')}}</el-button>
<el-button type="primary" size="small" @click="runTest">{{$t('commons.test')}}</el-button>
</div>
</el-col>
</el-row>
<!-- 基础信息 -->
<p class="tip">{{$t('test_track.plan_view.base_info')}} </p>
<br/>
<el-row>
<el-col>
<ms-basis-api :moduleOptions="moduleOptions" :basisData="basisData" ref="basicForm" @callback="saveApi"/>
</el-col>
</el-row>
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
</div>
</template>
<script>
import MsBasisApi from "./BasisApi";
import MsBasisParameters from "../request/database/BasisParameters";
export default {
name: "MsApiSqlRequestForm",
components: {
MsBasisApi, MsBasisParameters
},
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {}
},
methods: {
validateApi() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {
this.basisData.method = this.basisData.protocol;
this.$emit('saveApi', this.basisData);
},
runTest() {
},
},
}
</script>
<style scoped>
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 0px 20px 0px;
}
</style>

View File

@ -0,0 +1,78 @@
<template xmlns:el-col="http://www.w3.org/1999/html">
<!-- 操作按钮 -->
<div style="background-color: white;">
<el-row>
<el-col>
<!--操作按钮-->
<div style="float: right;margin-right: 20px;margin-top: 20px">
<el-button type="primary" size="small" @click="validateApi">{{$t('commons.save')}}</el-button>
<el-button type="primary" size="small" @click="runTest">{{$t('commons.test')}}</el-button>
</div>
</el-col>
</el-row>
<!-- 基础信息 -->
<p class="tip">{{$t('test_track.plan_view.base_info')}} </p>
<br/>
<el-row>
<el-col>
<ms-basis-api :moduleOptions="moduleOptions" :basisData="basisData" ref="basicForm" @callback="saveApi"/>
</el-col>
</el-row>
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
</div>
</template>
<script>
import MsBasisApi from "./BasisApi";
import MsBasisParameters from "../request/tcp/BasisParameters";
export default {
name: "MsAddCompleteTcpApi",
components: {MsBasisApi, MsBasisParameters},
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {}
},
methods: {
validateApi() {
this.basisData.method = "TCP";
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {
this.$emit('saveApi', this.basisData);
},
runTest() {
}
},
}
</script>
<style scoped>
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 0px 20px 0px;
}
</style>

View File

@ -1,311 +0,0 @@
<template xmlns:el-col="http://www.w3.org/1999/html">
<!-- 操作按钮 -->
<div style="background-color: white;">
<el-row>
<el-col>
<!--操作按钮-->
<div style="float: right;margin-right: 20px;margin-top: 20px">
<el-button type="primary" size="small" @click="validateApi">{{$t('commons.save')}}</el-button>
<el-button type="primary" size="small" @click="runTest">{{$t('commons.test')}}</el-button>
</div>
</el-col>
</el-row>
<!-- 基础信息 -->
<p class="tip">{{$t('test_track.plan_view.base_info')}} </p>
<br/>
<el-row>
<el-col>
<ms-basis-api :moduleOptions="moduleOptions" :basisData="basisData" ref="basicForm" @callback="saveApi"/>
</el-col>
</el-row>
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<el-row>
<el-col :span="21" style="padding-bottom: 50px">
<el-form class="tcp" :model="request" :rules="rules" ref="request" label-width="auto" :disabled="isReadOnly">
<el-form-item/>
<!-- <el-form-item :label="$t('api_test.request.name')" prop="name">
<el-input v-model="request.name" size="small" maxlength="300" show-word-limit/>
</el-form-item>-->
<el-form-item label="TCPClient" prop="classname">
<el-select v-model="request.classname" style="width: 100%" size="small">
<el-option v-for="c in classes" :key="c" :label="c" :value="c"/>
</el-select>
</el-form-item>
<el-row :gutter="10">
<el-col :span="16">
<el-form-item :label="$t('api_test.request.tcp.server')" prop="server">
<el-input v-model="request.server" maxlength="300" show-word-limit size="small"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('api_test.request.tcp.port')" prop="port" label-width="60px">
<el-input-number v-model="request.port" controls-position="right" :min="0" :max="65535" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.connect')" prop="ctimeout">
<el-input-number v-model="request.ctimeout" controls-position="right" :min="0" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.response')" prop="timeout">
<el-input-number v-model="request.timeout" controls-position="right" :min="0" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.so_linger')" prop="soLinger">
<el-input v-model="request.soLinger" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.eol_byte')" prop="eolByte">
<el-input v-model="request.eolByte" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item :label="$t('api_test.request.refer_to_environment')">
<el-switch
v-model="request.useEnvironment"
@change="useEnvironmentChange">
</el-switch>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.re_use_connection')">
<el-checkbox v-model="request.reUseConnection"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.close_connection')">
<el-checkbox v-model="request.closeConnection"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.no_delay')">
<el-checkbox v-model="request.nodelay"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">
<el-form-item :label="$t('api_test.request.tcp.username')" prop="username">
<el-input v-model="request.username" maxlength="100" show-word-limit size="small"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('api_test.request.tcp.password')" prop="password">
<el-input v-model="request.password" maxlength="30" show-word-limit show-password
autocomplete="new-password" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('api_test.request.tcp.request')" prop="request">
<div class="send-request">
<ms-code-edit mode="text" :read-only="isReadOnly" :data.sync="request.request"
:modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
</div>
</el-form-item>
</el-form>
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData" style="margin-left: 30px">
<!-- 前置脚本 -->
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="warning"
:jsr223-processor="row"/>
<!--后置脚本-->
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="success"
:jsr223-processor="row"/>
<!--断言规则-->
<ms-api-assertions v-if="row.type==='Assertions'" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/>
<!--提取规则-->
<ms-api-extract :is-read-only="isReadOnly" @remove="remove" v-if="row.type==='Extract'" :extract="row"/>
</div>
</el-col>
<el-col :span="3" class="ms-left-cell">
<el-button class="ms-left-buttion" size="small" type="warning" @click="addPre" plain>+{{$t('api_test.definition.request.pre_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="success" @click="addPost" plain>+{{$t('api_test.definition.request.post_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="danger" @click="addAssertions" plain>+{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="info" @click="addExtract" plain>+{{$t('api_test.definition.request.extract_param')}}</el-button>
</el-col>
</el-row>
</div>
</template>
<script>
import MsApiAssertions from "../assertion/ApiAssertions";
import MsApiExtract from "../extract/ApiExtract";
import MsJsr233Processor from "../processor/Jsr233Processor";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import TCPSampler from "../jmeter/components/sampler/tcp-sampler";
import {createComponent} from "../jmeter/components";
import {Assertions, Extract} from "../../model/ApiTestModel";
import {API_STATUS} from "../../model/JsonData";
import MsBasisApi from "./BasisApi";
export default {
name: "MsApiTcpRequestForm",
components: {MsCodeEdit, MsJsr233Processor, MsApiExtract, MsApiAssertions, MsBasisApi},
props: {
request: {},
basisData: {},
currentProject: {},
maintainerOptions: Array,
moduleOptions: Array,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
activeName: "assertions",
classes: TCPSampler.CLASSES,
rules: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
],
},
isReloadData: false,
options: API_STATUS,
}
},
methods: {
useEnvironmentChange(value) {
if (value && !this.request.environment) {
this.$error(this.$t('api_test.request.please_add_environment_to_scenario'), 2000);
this.request.useEnvironment = false;
}
this.$refs["request"].clearValidate();
},
addPre() {
let jsr223PreProcessor = createComponent("JSR223PreProcessor");
this.request.hashTree.push(jsr223PreProcessor);
this.reload();
},
addPost() {
let jsr223PostProcessor = createComponent("JSR223PostProcessor");
this.request.hashTree.push(jsr223PostProcessor);
this.reload();
},
addAssertions() {
let assertions = new Assertions();
this.request.hashTree.push(assertions);
this.reload();
},
addExtract() {
let jsonPostProcessor = new Extract();
this.request.hashTree.push(jsonPostProcessor);
this.reload();
},
remove(row) {
let index = this.request.hashTree.indexOf(row);
this.request.hashTree.splice(index, 1);
this.reload();
},
reload() {
this.isReloadData = true
this.$nextTick(() => {
this.isReloadData = false
})
},
setParameter() {
this.request.modulePath = this.getPath(this.basisData.moduleId);
this.request.useEnvironment = undefined;
},
getPath(id) {
if (id === null) {
return null;
}
let path = this.moduleOptions.filter(function (item) {
return item.id === id ? item.path : "";
});
return path[0].path;
},
validateApi() {
this.basisData.method = "TCP";
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {
this.$emit('saveApi', this.request);
},
runTest() {
alert(444);
}
},
}
</script>
<style scoped>
.tcp >>> .el-input-number {
width: 100%;
}
.send-request {
padding: 0px 0;
height: 300px;
border: 1px #DCDFE6 solid;
border-radius: 4px;
width: 100%;
}
.ms-left-cell {
margin-top: 40px;
}
.ms-left-buttion {
margin: 6px 0px 8px 30px;
}
.ms-query {
background: #7F7F7F;
color: white;
height: 18px;
border-radius: 42%;
}
.ms-header {
background: #783887;
color: white;
height: 18px;
border-radius: 42%;
}
/deep/ .el-form-item {
margin-bottom: 15px;
}
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 0px 20px 0px;
}
</style>

View File

@ -0,0 +1,163 @@
<template>
<div class="card-container">
<el-card class="card-content">
<el-form :model="debugForm" :rules="rules" ref="debugForm" :inline="true" label-position="right">
<p class="tip">{{$t('test_track.plan_view.base_info')}} </p>
<el-form-item :label="$t('api_report.request')" prop="url">
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-model="debugForm.url"
class="ms-http-input" size="small">
<el-select v-model="debugForm.method" slot="prepend" style="width: 100px" size="small">
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-input>
</el-form-item>
<el-form-item>
<el-dropdown split-button type="primary" class="ms-api-buttion" @click="handleCommand"
@command="handleCommand" size="small">
{{$t('commons.test')}}
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="save_as">{{$t('api_test.definition.request.save_as')}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-form-item>
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- HTTP 请求参数 -->
<ms-api-request-form :headers="headers" :request="request"/>
</el-form>
<!-- HTTP 请求返回数据 -->
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
<ms-request-result-tail v-loading="loading" :response="responseData" ref="debugResult"/>
<!-- 执行组件 -->
<ms-run :debug="true" :reportId="reportId" :run-data="runData" @runRefresh="runRefresh" ref="runTest"/>
</el-card>
</div>
</template>
<script>
import MsApiRequestForm from "../request/http/ApiRequestForm";
import MsResponseResult from "../response/ResponseResult";
import MsRequestMetric from "../response/RequestMetric";
import {getUUID, getCurrentUser} from "@/common/js/utils";
import MsResponseText from "../response/ResponseText";
import MsRun from "../Run";
import {createComponent, Request} from "../jmeter/components";
import HeaderManager from "../jmeter/components/configurations/header-manager";
import {REQ_METHOD} from "../../model/JsonData";
import MsRequestResultTail from "../response/RequestResultTail";
export default {
name: "ApiConfig",
components: {MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun},
props: {
currentProtocol: String,
},
data() {
return {
rules: {
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
url: [{required: true, message: this.$t('api_test.definition.request.path_all_info'), trigger: 'blur'}],
},
debugForm: {method: REQ_METHOD[0].id},
options: [],
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
loading: false,
debugResultId: "",
runData: [],
headers: [],
reportId: "",
reqOptions: REQ_METHOD,
request: {},
}
},
created() {
switch (this.protocol) {
case Request.TYPES.SQL:
this.request = createComponent("SQL");
break;
case Request.TYPES.DUBBO:
this.request = createComponent("JDBCSampler");
break;
case Request.TYPES.TCP:
this.request = createComponent("TCPSampler");
break;
default:
this.createHttp();
break;
}
},
watch: {
debugResultId() {
this.getResult()
}
},
methods: {
handleCommand(e) {
if (e === "save_as") {
this.saveAs();
} else {
this.runDebug();
}
},
createHttp() {
let header = createComponent("HeaderManager");
this.request = createComponent("HTTPSamplerProxy");
this.request.hashTree = [header];
},
runDebug() {
this.$refs['debugForm'].validate((valid) => {
if (valid) {
this.loading = true;
this.request.url = this.debugForm.url;
this.request.method = this.debugForm.method;
this.request.hashTree[0].headers = this.headers;
this.request.name = getUUID().substring(0, 8);
this.runData = [];
this.runData.push(this.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
}
})
},
runRefresh(data) {
this.responseData = data;
this.loading = false;
this.$refs.debugResult.reload();
},
saveAs() {
this.$refs['debugForm'].validate((valid) => {
if (valid) {
this.debugForm.request = JSON.stringify(this.request);
this.debugForm.userId = getCurrentUser().id;
this.debugForm.status = "Underway";
this.debugForm.protocol = this.currentProtocol;
this.$emit('saveAs', this.debugForm);
}
else {
return false;
}
})
}
}
}
</script>
<style scoped>
.ms-http-input {
width: 500px;
margin-top: 5px;
}
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 20px 0;
}
</style>

View File

@ -15,7 +15,7 @@
<script> <script>
import {CommonConfig, Environment} from "../../model/EnvironmentModel"; import {CommonConfig, Environment} from "../../model/EnvironmentModel";
import MsApiScenarioVariables from "./ApiScenarioVariables"; import MsApiScenarioVariables from "../ApiScenarioVariables";
import MsApiHostTable from "./ApiHostTable"; import MsApiHostTable from "./ApiHostTable";
export default { export default {

View File

@ -35,7 +35,7 @@
</template> </template>
<script> <script>
import MsApiScenarioVariables from "./ApiScenarioVariables"; import MsApiScenarioVariables from "../ApiScenarioVariables";
import MsApiKeyValue from "../ApiKeyValue"; import MsApiKeyValue from "../ApiKeyValue";
import MsDialogFooter from "../../../../common/components/MsDialogFooter"; import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {REQUEST_HEADERS} from "@/common/js/constants"; import {REQUEST_HEADERS} from "@/common/js/constants";

View File

@ -0,0 +1,38 @@
import Sampler from "../sampler";
import {ConfigCenter, ConsumerAndService, RegistryCenter} from "../../../../../model/ApiTestModel";
const DEFAULT_OPTIONS = {
options: {
attributes: {
guiclass: "DubboSampleGui",
testclass: "DubboSampler",
testname: "DubboSampler",
enabled: "true"
},
}
};
export default class DubboSampler extends Sampler {
static PROTOCOLS = {
DUBBO: "dubbo://",
RMI: "rmi://",
}
constructor(options = DEFAULT_OPTIONS) {
super(options);
this.type = "DubboSampler";
this.hashTree = [];
this.protocol = options.protocol || DubboSampler.PROTOCOLS.DUBBO;
this.interface = options.interface;
this.method = options.method;
this.configCenter = new ConfigCenter(options.configCenter);
this.registryCenter = new RegistryCenter(options.registryCenter);
this.consumerAndService = new ConsumerAndService(options.consumerAndService);
this.args = [];
this.attachmentArgs = [];
this.dubboConfig = undefined;
this.debugReport = undefined;
}
}
export const schema = {
DubboSampler: DubboSampler
}

View File

@ -14,17 +14,19 @@ const DEFAULT_OPTIONS = {
export default class JDBCSampler extends Sampler { export default class JDBCSampler extends Sampler {
constructor(options = DEFAULT_OPTIONS) { constructor(options = DEFAULT_OPTIONS) {
super(options); super(options);
this.type = "JDBCSampler";
this.dataSource = this.initStringProp("dataSource") this.hashTree = [];
this.query = this.initStringProp("query") this.variables = [];
this.queryType = this.initStringProp("queryType") this.dataSource = undefined;
this.queryArguments = this.initStringProp("queryArguments") this.query = undefined;
this.queryArgumentsTypes = this.initStringProp("queryArgumentsTypes") this.queryType = undefined;
this.queryTimeout = this.initStringProp("queryTimeout") this.queryArguments = undefined;
this.resultSetHandler = this.initStringProp("resultSetHandler") this.queryArgumentsTypes = undefined;
this.resultSetMaxRows = this.initStringProp("resultSetMaxRows") this.queryTimeout = undefined;
this.resultVariable = this.initStringProp("resultVariable") this.resultSetHandler = undefined;
this.variableNames = this.initStringProp("variableNames") this.resultSetMaxRows = undefined;
this.resultVariable = undefined;
this.variableNames = undefined;
} }
} }

View File

@ -0,0 +1,263 @@
<template>
<div>
<el-row>
<el-col :span="21" style="padding-bottom: 50px">
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin: 20px">
<el-form :model="request" ref="request" label-width="100px" :disabled="isReadOnly" style="margin: 20px">
<div class="one-row">
<el-form-item prop="environmentId" :label="$t('api_test.definition.request.run_env')">
<el-select v-model="request.environmentId" size="small" class="ms-htt-width"
:placeholder="$t('api_test.definition.request.run_env')"
@change="environmentChange" clearable>
<el-option v-for="(environment, index) in environments" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/>
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
<template v-slot:empty>
<div class="empty-environment">
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
</div>
</template>
</el-select>
</el-form-item>
<el-form-item :label="$t('api_test.request.sql.dataSource')" prop="dataSource" style="margin-left: 10px">
<el-select v-model="request.dataSource" size="small">
<el-option v-for="(item, index) in databaseConfigsOptions" :key="index" :value="item" :label="item.name"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('api_test.request.sql.timeout')" prop="queryTimeout" style="margin-left: 10px">
<el-input-number :disabled="isReadOnly" size="small" v-model="request.queryTimeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0"/>
</el-form-item>
</div>
<el-form-item :label="$t('api_test.request.sql.result_variable')" prop="resultVariable">
<el-input v-model="request.resultVariable" maxlength="300" show-word-limit/>
</el-form-item>
<el-form-item :label="$t('api_test.request.sql.variable_names')" prop="variableNames">
<el-input v-model="request.variableNames" maxlength="300" show-word-limit/>
</el-form-item>
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('api_test.scenario.variables')" name="variables">
<ms-api-scenario-variables :is-read-only="isReadOnly" :items="request.variables"
:description="$t('api_test.scenario.kv_description')"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.sql.sql_script')" name="sql">
<div class="sql-content">
<ms-code-edit mode="sql" :read-only="isReadOnly" :modes="['sql']" :data.sync="request.query" theme="eclipse" ref="codeEdit"/>
</div>
</el-tab-pane>
</el-tabs>
</el-form>
</div>
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData" style="margin-left: 20px;width: 100%">
<!-- 前置脚本 -->
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="warning"
:jsr223-processor="row"/>
<!--后置脚本-->
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="success"
:jsr223-processor="row"/>
<!--断言规则-->
<ms-api-assertions v-if="row.type==='Assertions'" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/>
<!--提取规则-->
<ms-api-extract :is-read-only="isReadOnly" @remove="remove" v-if="row.type==='Extract'" :extract="row"/>
</div>
</el-col>
<el-col :span="3" class="ms-left-cell">
<el-button class="ms-left-buttion" size="small" type="warning" @click="addPre" plain>+{{$t('api_test.definition.request.pre_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="success" @click="addPost" plain>+{{$t('api_test.definition.request.post_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="danger" @click="addAssertions" plain>+{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="info" @click="addExtract" plain>+{{$t('api_test.definition.request.extract_param')}}</el-button>
</el-col>
</el-row>
<!-- 环境 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
</div>
</template>
<script>
import MsApiKeyValue from "../../ApiKeyValue";
import MsApiAssertions from "../../assertion/ApiAssertions";
import MsApiExtract from "../../extract/ApiExtract";
import ApiRequestMethodSelect from "../../collapse/ApiRequestMethodSelect";
import MsJsr233Processor from "../../processor/Jsr233Processor";
import MsCodeEdit from "../../../../../common/components/MsCodeEdit";
import MsApiScenarioVariables from "../../ApiScenarioVariables";
import {createComponent} from "../../jmeter/components";
import {Assertions, Extract} from "../../../model/ApiTestModel";
import {parseEnvironment} from "../../../model/EnvironmentModel";
import ApiEnvironmentConfig from "../../environment/ApiEnvironmentConfig";
export default {
name: "MsDatabaseConfig",
components: {
MsApiScenarioVariables,
MsCodeEdit,
MsJsr233Processor, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiKeyValue, ApiEnvironmentConfig
},
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
default: false
},
},
data() {
return {
environments: [],
databaseConfigsOptions: [],
isReloadData: false,
activeName: "variables",
}
},
created() {
this.getEnvironments();
},
methods: {
addPre() {
let jsr223PreProcessor = createComponent("JSR223PreProcessor");
this.request.hashTree.push(jsr223PreProcessor);
this.reload();
},
addPost() {
let jsr223PostProcessor = createComponent("JSR223PostProcessor");
this.request.hashTree.push(jsr223PostProcessor);
this.reload();
},
addAssertions() {
let assertions = new Assertions();
this.request.hashTree.push(assertions);
this.reload();
},
addExtract() {
let jsonPostProcessor = new Extract();
this.request.hashTree.push(jsonPostProcessor);
this.reload();
},
remove(row) {
let index = this.request.hashTree.indexOf(row);
this.request.hashTree.splice(index, 1);
this.reload();
},
reload() {
this.isReloadData = true
this.$nextTick(() => {
this.isReloadData = false
})
},
validateApi() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {
this.basisData.method = this.basisData.protocol;
this.$emit('saveApi', this.basisData);
},
runTest() {
},
getEnvironments() {
if (this.currentProject) {
this.environments = [];
this.$get('/api/environment/list/' + this.currentProject.id, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
this.initDataSource();
});
}
},
openEnvironmentConfig() {
if (!this.currentProject) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
},
initDataSource() {
for (let i in this.environments) {
if (this.environments[i].id === this.request.environmentId) {
this.databaseConfigsOptions = [];
this.environments[i].config.databaseConfigs.forEach(item => {
this.databaseConfigsOptions.push(item);
})
break;
}
}
},
environmentChange(value) {
this.request.dataSource = undefined;
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.databaseConfigsOptions = [];
this.environments[i].config.databaseConfigs.forEach(item => {
this.databaseConfigsOptions.push(item);
})
break;
}
}
},
environmentConfigClose() {
this.getEnvironments();
},
}
}
</script>
<style scoped>
.sql-content {
height: calc(100vh - 570px);
}
.one-row .el-form-item {
display: inline-block;
}
.one-row .el-form-item:nth-child(2) {
margin-left: 60px;
}
.ms-left-cell {
margin-top: 40px;
}
.ms-left-buttion {
margin: 6px 0px 8px 30px;
}
/deep/ .el-form-item {
margin-bottom: 15px;
}
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 0px 20px 0px;
}
</style>

View File

@ -0,0 +1,200 @@
<template>
<div>
<el-row>
<el-col :span="21" style="padding-bottom: 50px">
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin: 20px">
<el-form :model="request" ref="request" label-width="100px" :disabled="isReadOnly" style="margin: 20px">
<el-form-item :label="$t('api_test.request.dubbo.protocol')" prop="protocol">
<el-select v-model="request.protocol" size="small">
<el-option label="dubbo://" :value="protocols.DUBBO"/>
</el-select>
</el-form-item>
<el-tabs v-model="activeName">
<el-tab-pane label="Interface" name="interface">
<ms-dubbo-interface :request="request" :is-read-only="isReadOnly"/>
</el-tab-pane>
<el-tab-pane label="Config Center" name="config">
<ms-dubbo-config-center :config="request.configCenter" :is-read-only="isReadOnly"
:description="$t('api_test.request.dubbo.form_description')"/>
</el-tab-pane>
<el-tab-pane label="Registry Center" name="registry">
<ms-dubbo-registry-center :registry="request.registryCenter" :is-read-only="isReadOnly"
:description="$t('api_test.request.dubbo.form_description')"/>
</el-tab-pane>
<el-tab-pane label="Consumer & Service" name="consumer">
<ms-dubbo-consumer-service :consumer="request.consumerAndService" :is-read-only="isReadOnly"
:description="$t('api_test.request.dubbo.form_description')"/>
</el-tab-pane>
<el-tab-pane label="Args" name="args">
<ms-api-key-value :is-read-only="isReadOnly" :items="request.args"
key-placeholder="Param Type" value-placeholder="Param Value"/>
</el-tab-pane>
<el-tab-pane label="Attachment Args" name="attachment">
<ms-api-key-value :is-read-only="isReadOnly" :items="request.attachmentArgs"/>
</el-tab-pane>
</el-tabs>
</el-form>
</div>
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData" style="margin-left: 20px;width: 100%">
<!-- 前置脚本 -->
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="warning"
:jsr223-processor="row"/>
<!--后置脚本-->
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="success"
:jsr223-processor="row"/>
<!--断言规则-->
<ms-api-assertions v-if="row.type==='Assertions'" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/>
<!--提取规则-->
<ms-api-extract :is-read-only="isReadOnly" @remove="remove" v-if="row.type==='Extract'" :extract="row"/>
</div>
</el-col>
<el-col :span="3" class="ms-left-cell">
<el-button class="ms-left-buttion" size="small" type="warning" @click="addPre" plain>+{{$t('api_test.definition.request.pre_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="success" @click="addPost" plain>+{{$t('api_test.definition.request.post_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="danger" @click="addAssertions" plain>+{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="info" @click="addExtract" plain>+{{$t('api_test.definition.request.extract_param')}}</el-button>
</el-col>
</el-row>
</div>
</template>
<script>
import MsApiKeyValue from "../../ApiKeyValue";
import MsApiAssertions from "../../assertion/ApiAssertions";
import MsApiExtract from "../../extract/ApiExtract";
import ApiRequestMethodSelect from "../../collapse/ApiRequestMethodSelect";
import MsJsr233Processor from "../../processor/Jsr233Processor";
import MsCodeEdit from "../../../../../common/components/MsCodeEdit";
import MsApiScenarioVariables from "../../ApiScenarioVariables";
import {createComponent} from "../../jmeter/components";
import {Assertions, Extract, DubboRequest} from "../../../model/ApiTestModel";
import {parseEnvironment} from "../../../model/EnvironmentModel";
import MsDubboInterface from "../../request/dubbo/Interface";
import MsDubboRegistryCenter from "../../request/dubbo/RegistryCenter";
import MsDubboConfigCenter from "../../request/dubbo/ConfigCenter";
import MsDubboConsumerService from "../../request/dubbo/ConsumerAndService";
export default {
name: "MsDatabaseConfig",
components: {
MsApiScenarioVariables,
MsCodeEdit,
MsJsr233Processor, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiKeyValue, MsDubboConsumerService,
MsDubboConfigCenter,
MsDubboRegistryCenter,
MsDubboInterface,
},
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
default: false
},
},
data() {
return {
activeName: "interface",
activeName2: "args",
protocols: DubboRequest.PROTOCOLS,
isReloadData: false,
}
},
methods: {
addPre() {
let jsr223PreProcessor = createComponent("JSR223PreProcessor");
this.request.hashTree.push(jsr223PreProcessor);
this.reload();
},
addPost() {
let jsr223PostProcessor = createComponent("JSR223PostProcessor");
this.request.hashTree.push(jsr223PostProcessor);
this.reload();
},
addAssertions() {
let assertions = new Assertions();
this.request.hashTree.push(assertions);
this.reload();
},
addExtract() {
let jsonPostProcessor = new Extract();
this.request.hashTree.push(jsonPostProcessor);
this.reload();
},
remove(row) {
let index = this.request.hashTree.indexOf(row);
this.request.hashTree.splice(index, 1);
this.reload();
},
reload() {
this.isReloadData = true
this.$nextTick(() => {
this.isReloadData = false
})
},
validateApi() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {
this.basisData.method = this.basisData.protocol;
this.$emit('saveApi', this.basisData);
},
runTest() {
},
}
}
</script>
<style scoped>
.one-row .el-form-item {
display: inline-block;
}
.one-row .el-form-item:nth-child(2) {
margin-left: 60px;
}
.ms-left-cell {
margin-top: 40px;
}
.ms-left-buttion {
margin: 6px 0px 8px 30px;
}
/deep/ .el-form-item {
margin-bottom: 15px;
}
.ms-left-cell {
margin-top: 40px;
}
.ms-left-buttion {
margin: 6px 0px 8px 30px;
}
/deep/ .el-form-item {
margin-bottom: 15px;
}
</style>

View File

@ -0,0 +1,83 @@
<template>
<el-form :model="config" :rules="rules" ref="config" label-width="100px" size="small" :disabled="isReadOnly">
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
<el-select v-model="config.protocol" class="select-100" clearable>
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
</el-select>
</el-form-item>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="config.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Namespace" prop="namespace" class="dubbo-form-item">
<el-input v-model="config.namespace" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="config.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Address" prop="address" class="dubbo-form-item-long">
<el-input v-model="config.address" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="UserName" prop="username" class="dubbo-form-item">
<el-input v-model="config.username" maxlength="100" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Password" prop="password" class="dubbo-form-item">
<el-input v-model="config.password" maxlength="30" show-word-limit show-password autocomplete="new-password"
:placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-form>
</template>
<script>
import './dubbo.css'
import {ConfigCenter} from "@/business/components/api/definition/model/ApiTestModel";
export default {
name: "MsDubboConfigCenter",
props: {
description: String,
config: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
protocols: ConfigCenter.PROTOCOLS,
methods: [],
rules: {
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
namespace: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
username: [
{max: 100, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
password: [
{max: 30, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
address: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
}
}
}
}
</script>

View File

@ -0,0 +1,82 @@
<template>
<el-form :model="consumer" :rules="rules" ref="consumer" label-width="100px" size="small" :disabled="isReadOnly">
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="consumer.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Version" prop="version" class="dubbo-form-item">
<el-input v-model="consumer.version" maxlength="30" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Retries" prop="retries" class="dubbo-form-item">
<el-input type="number" v-model="consumer.retries" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Cluster" prop="cluster" class="dubbo-form-item">
<el-input v-model="consumer.cluster" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="consumer.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Connections" prop="connections" class="dubbo-form-item">
<el-input type="number" v-model="consumer.connections" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Async" prop="async" class="dubbo-form-item">
<el-select v-model="consumer.async" class="select-100" clearable>
<el-option v-for="option in asyncOptions" :key="option" :label="option" :value="option"/>
</el-select>
</el-form-item>
<el-form-item label="LoadBalance" prop="loadBalance" class="dubbo-form-item">
<el-select v-model="consumer.loadBalance" class="select-100" clearable>
<el-option v-for="option in loadBalances" :key="option" :label="option" :value="option"/>
</el-select>
</el-form-item>
</el-form>
</template>
<script>
import './dubbo.css'
import {ConsumerAndService, RegistryCenter} from "@/business/components/api/definition/model/ApiTestModel";
export default {
name: "MsDubboConsumerService",
props: {
description: String,
consumer: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
asyncOptions: ConsumerAndService.ASYNC_OPTIONS,
loadBalances: ConsumerAndService.LOAD_BALANCE_OPTIONS,
methods: [],
rules: {
version: [
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
],
cluster: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
}
}
}
}
</script>

View File

@ -0,0 +1,124 @@
<template>
<el-form :model="request" :rules="rules" ref="request" label-width="100px" size="small" v-loading="loading"
:disabled="isReadOnly">
<el-button class="get-provider" type="primary" size="small" @click="getProviderList">Get Provider List</el-button>
<el-row>
<el-col :span="12">
<el-form-item label="Interfaces" prop="interfaces">
<el-select v-model="serviceInterface" class="select-100" @change="changeInterface" :disabled="isDisable">
<el-option v-for="i in interfaces" :key="i.value" :label="i.label" :value="i.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Methods" prop="methods">
<el-select v-model="method" class="select-100" @change="changeMethod" :disabled="isDisable">
<el-option v-for="m in methods" :key="m" :label="m" :value="m"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="Interface" prop="interface">
<el-input v-model="request.interface" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Method" prop="method">
<el-input v-model="request.method" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: "MsDubboInterface",
props: {
request: {},
registryCenter: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false,
providerMap: {},
serviceInterface: "",
method: "",
interfaces: [],
methods: [],
rules: {
interface: [
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
],
method: [
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
]
}
}
},
methods: {
changeInterface(value) {
this.methods = this.providerMap[value].methods;
this.request.interface = value;
this.request.consumerAndService.version = this.providerMap[value].version;
},
changeMethod(value) {
this.request.method = value;
},
getProviderList() {
if (this.request.registryCenter === undefined || this.request.dubboConfig ===undefined) {
return;
}
let param = {
protocol: this.request.registryCenter.protocol || this.request.dubboConfig.registryCenter.protocol,
address: this.request.registryCenter.address || this.request.dubboConfig.registryCenter.address,
group: this.request.registryCenter.group || this.request.dubboConfig.registryCenter.group,
};
this.loading = true;
this.$post("/api/dubbo/providers", param).then(response => {
this.methodMap = {};
this.interfaces = [];
response.data.data.forEach(p => {
this.providerMap[p.serviceInterface] = p;
this.interfaces.push({label: p.service, value: p.serviceInterface})
});
if (this.methodMap[this.request.interface]) {
this.methods = this.methodMap[this.request.interface].methods;
}
this.loading = false;
this.$success(this.$t('api_test.request.dubbo.get_provider_success'));
}).catch(() => {
this.loading = false;
this.$warning(this.$t('api_test.request.dubbo.check_registry_center'));
});
}
},
computed: {
isDisable() {
return this.interfaces.length === 0;
}
}
}
</script>
<style scoped>
.get-provider {
margin-bottom: 22px;
}
.select-100 {
width: 100%;
}
</style>

View File

@ -0,0 +1,73 @@
<template>
<el-form :model="registry" :rules="rules" ref="registry" label-width="100px" size="small" :disabled="isReadOnly">
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
<el-select v-model="registry.protocol" class="select-100" clearable>
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
</el-select>
</el-form-item>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="registry.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="UserName" prop="username" class="dubbo-form-item">
<el-input v-model="registry.username" maxlength="100" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Password" prop="password" class="dubbo-form-item">
<el-input v-model="registry.password" maxlength="30" show-word-limit show-password autocomplete="new-password"
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Address" prop="address" class="dubbo-form-item-long">
<el-input v-model="registry.address" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="registry.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-form>
</template>
<script>
import './dubbo.css'
import {RegistryCenter} from "@/business/components/api/definition/model/ApiTestModel";
export default {
name: "MsDubboRegistryCenter",
props: {
description: String,
registry: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
protocols: RegistryCenter.PROTOCOLS,
methods: [],
rules: {
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
username: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
password: [
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
],
address: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
}
}
}
}
</script>

View File

@ -0,0 +1,43 @@
@media only screen and (max-width: 1200px) {
.dubbo-form-item {
width: 50%;
}
.dubbo-form-item-long {
width: 100%;
}
}
@media only screen and (min-width: 1201px) and (max-width: 1600px) {
.dubbo-form-item {
width: 33.33%;
}
.dubbo-form-item-long {
width: 66.67%;
}
}
@media only screen and (min-width: 1601px) {
.dubbo-form-item {
width: 25%;
}
.dubbo-form-item-long {
width: 50%;
}
}
.dubbo-form-item, .dubbo-form-item-long {
display: inline-block;
}
.select-100 {
width: 100%;
}
.dubbo-form-description {
width: 100%;
font-size: 13px;
margin-bottom: 12px;
}

View File

@ -0,0 +1,299 @@
<template>
<div>
<el-row>
<el-col :span="21" style="padding-bottom: 50px">
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin: 20px">
<el-form class="tcp" :model="request" ref="request" label-width="auto" :disabled="isReadOnly" style="margin: 20px">
<el-row :gutter="10">
<el-col :span="9">
<el-form-item label="TCPClient" prop="classname">
<el-select v-model="request.classname" style="width: 100%" size="small">
<el-option v-for="c in classes" :key="c" :label="c" :value="c"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item :label="$t('api_test.request.tcp.server')" prop="server">
<el-input v-model="request.server" maxlength="300" show-word-limit size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.port')" prop="port" label-width="60px">
<el-input-number v-model="request.port" controls-position="right" :min="0" :max="65535" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="9">
<el-form-item :label="$t('api_test.request.tcp.connect')" prop="ctimeout">
<el-input-number v-model="request.ctimeout" controls-position="right" :min="0" size="small"/>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item :label="$t('api_test.request.tcp.response')" prop="timeout">
<el-input-number v-model="request.timeout" controls-position="right" :min="0" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.so_linger')" prop="soLinger">
<el-input v-model="request.soLinger" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="9">
<el-form-item :label="$t('api_test.request.tcp.username')" prop="username">
<el-input v-model="request.username" maxlength="100" show-word-limit size="small"/>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item :label="$t('api_test.request.tcp.password')" prop="password">
<el-input v-model="request.password" maxlength="30" show-word-limit show-password
autocomplete="new-password" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.eol_byte')" prop="eolByte">
<el-input v-model="request.eolByte" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10" style="margin-left: 30px">
<el-col :span="9">
<el-form-item :label="$t('api_test.request.tcp.re_use_connection')">
<el-checkbox v-model="request.reUseConnection"/>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item :label="$t('api_test.request.tcp.close_connection')">
<el-checkbox v-model="request.closeConnection"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.no_delay')">
<el-checkbox v-model="request.nodelay"/>
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('api_test.request.tcp.request')" prop="request">
<div class="send-request">
<ms-code-edit mode="text" :read-only="isReadOnly" :data.sync="request.request"
:modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
</div>
</el-form-item>
</el-form>
</div>
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData" style="margin-left: 20px;width: 100%">
<!-- 前置脚本 -->
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="warning"
:jsr223-processor="row"/>
<!--后置脚本-->
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="success"
:jsr223-processor="row"/>
<!--断言规则-->
<ms-api-assertions v-if="row.type==='Assertions'" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/>
<!--提取规则-->
<ms-api-extract :is-read-only="isReadOnly" @remove="remove" v-if="row.type==='Extract'" :extract="row"/>
</div>
</el-col>
<el-col :span="3" class="ms-left-cell">
<el-button class="ms-left-buttion" size="small" type="warning" @click="addPre" plain>+{{$t('api_test.definition.request.pre_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="success" @click="addPost" plain>+{{$t('api_test.definition.request.post_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="danger" @click="addAssertions" plain>+{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="info" @click="addExtract" plain>+{{$t('api_test.definition.request.extract_param')}}</el-button>
</el-col>
</el-row>
</div>
</template>
<script>
import MsApiKeyValue from "../../ApiKeyValue";
import MsApiAssertions from "../../assertion/ApiAssertions";
import MsApiExtract from "../../extract/ApiExtract";
import ApiRequestMethodSelect from "../../collapse/ApiRequestMethodSelect";
import MsJsr233Processor from "../../processor/Jsr233Processor";
import MsCodeEdit from "../../../../../common/components/MsCodeEdit";
import MsApiScenarioVariables from "../../ApiScenarioVariables";
import {createComponent} from "../../jmeter/components";
import {Assertions, Extract} from "../../../model/ApiTestModel";
import {parseEnvironment} from "../../../model/EnvironmentModel";
import ApiEnvironmentConfig from "../../environment/ApiEnvironmentConfig";
import {API_STATUS} from "../../../model/JsonData";
import TCPSampler from "../../jmeter/components/sampler/tcp-sampler";
export default {
name: "MsDatabaseConfig",
components: {
MsApiScenarioVariables,
MsCodeEdit,
MsJsr233Processor, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiKeyValue, ApiEnvironmentConfig
},
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
default: false
},
},
data() {
return {
activeName: "assertions",
classes: TCPSampler.CLASSES,
isReloadData: false,
options: API_STATUS,
}
},
created() {
this.getEnvironments();
},
methods: {
addPre() {
let jsr223PreProcessor = createComponent("JSR223PreProcessor");
this.request.hashTree.push(jsr223PreProcessor);
this.reload();
},
addPost() {
let jsr223PostProcessor = createComponent("JSR223PostProcessor");
this.request.hashTree.push(jsr223PostProcessor);
this.reload();
},
addAssertions() {
let assertions = new Assertions();
this.request.hashTree.push(assertions);
this.reload();
},
addExtract() {
let jsonPostProcessor = new Extract();
this.request.hashTree.push(jsonPostProcessor);
this.reload();
},
remove(row) {
let index = this.request.hashTree.indexOf(row);
this.request.hashTree.splice(index, 1);
this.reload();
},
reload() {
this.isReloadData = true
this.$nextTick(() => {
this.isReloadData = false
})
},
validateApi() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {
this.basisData.method = this.basisData.protocol;
this.$emit('saveApi', this.basisData);
},
runTest() {
},
getEnvironments() {
if (this.currentProject) {
this.environments = [];
this.$get('/api/environment/list/' + this.currentProject.id, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
this.initDataSource();
});
}
},
openEnvironmentConfig() {
if (!this.currentProject) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
},
initDataSource() {
for (let i in this.environments) {
if (this.environments[i].id === this.request.environmentId) {
this.databaseConfigsOptions = [];
this.environments[i].config.databaseConfigs.forEach(item => {
this.databaseConfigsOptions.push(item);
})
break;
}
}
},
environmentChange(value) {
this.request.dataSource = undefined;
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.databaseConfigsOptions = [];
this.environments[i].config.databaseConfigs.forEach(item => {
this.databaseConfigsOptions.push(item);
})
break;
}
}
},
environmentConfigClose() {
this.getEnvironments();
},
}
}
</script>
<style scoped>
.tcp >>> .el-input-number {
width: 100%;
}
.send-request {
padding: 0px 0;
height: 300px;
border: 1px #DCDFE6 solid;
border-radius: 4px;
width: 100%;
}
.ms-left-cell {
margin-top: 40px;
}
.ms-left-buttion {
margin: 6px 0px 8px 30px;
}
/deep/ .el-form-item {
margin-bottom: 15px;
}
.ms-left-cell {
margin-top: 40px;
}
.ms-left-buttion {
margin: 6px 0px 8px 30px;
}
/deep/ .el-form-item {
margin-bottom: 15px;
}
</style>

View File

@ -87,7 +87,7 @@ import {TCPConfig} from "../../../model/ApiTestModel";
export default { export default {
name: "MsTcpConfig", name: "MsTcpConfig",
props: { props: {
config: TCPConfig, config: {},
isReadOnly: { isReadOnly: {
type: Boolean, type: Boolean,
default: false default: false