feat(接口测试): sql 请求
This commit is contained in:
parent
37bf65ce07
commit
cbb1976f77
|
@ -165,6 +165,12 @@
|
||||||
<version>${jmeter.version}</version>
|
<version>${jmeter.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.jmeter</groupId>
|
||||||
|
<artifactId>ApacheJMeter_jdbc</artifactId>
|
||||||
|
<version>${jmeter.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Zookeeper -->
|
<!-- Zookeeper -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package io.metersphere.api.dto.scenario;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DatabaseConfig {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private long poolMax;
|
||||||
|
private long timeout;
|
||||||
|
private String driver;
|
||||||
|
private String dbUrl;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
}
|
|
@ -16,5 +16,6 @@ public class Scenario {
|
||||||
private List<KeyValue> headers;
|
private List<KeyValue> headers;
|
||||||
private List<Request> requests;
|
private List<Request> requests;
|
||||||
private DubboConfig dubboConfig;
|
private DubboConfig dubboConfig;
|
||||||
|
private List<DatabaseConfig> databaseConfigs;
|
||||||
private Boolean enable;
|
private Boolean enable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
|
||||||
@JsonSubTypes({
|
@JsonSubTypes({
|
||||||
@JsonSubTypes.Type(value = HttpRequest.class, name = RequestType.HTTP),
|
@JsonSubTypes.Type(value = HttpRequest.class, name = RequestType.HTTP),
|
||||||
@JsonSubTypes.Type(value = DubboRequest.class, name = RequestType.DUBBO)
|
@JsonSubTypes.Type(value = DubboRequest.class, name = RequestType.DUBBO),
|
||||||
|
@JsonSubTypes.Type(value = SqlRequest.class, name = RequestType.SQL)
|
||||||
})
|
})
|
||||||
@JSONType(seeAlso = {HttpRequest.class, DubboRequest.class}, typeKey = "type")
|
@JSONType(seeAlso = {HttpRequest.class, DubboRequest.class, SqlRequest.class}, typeKey = "type")
|
||||||
public interface Request {
|
public interface Request {
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,4 +5,6 @@ public class RequestType {
|
||||||
public static final String HTTP = "HTTP";
|
public static final String HTTP = "HTTP";
|
||||||
|
|
||||||
public static final String DUBBO = "DUBBO";
|
public static final String DUBBO = "DUBBO";
|
||||||
|
|
||||||
|
public static final String SQL = "SQL";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package io.metersphere.api.dto.scenario.request;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
|
import io.metersphere.api.dto.scenario.assertions.Assertions;
|
||||||
|
import io.metersphere.api.dto.scenario.extract.Extract;
|
||||||
|
import io.metersphere.api.dto.scenario.processor.JSR223PostProcessor;
|
||||||
|
import io.metersphere.api.dto.scenario.processor.JSR223PreProcessor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JSONType(typeName = RequestType.SQL)
|
||||||
|
public class SqlRequest implements Request {
|
||||||
|
// type 必须放最前面,以便能够转换正确的类
|
||||||
|
private String type = RequestType.SQL;
|
||||||
|
@JSONField(ordinal = 1)
|
||||||
|
private String id;
|
||||||
|
@JSONField(ordinal = 2)
|
||||||
|
private String name;
|
||||||
|
@JSONField(ordinal = 3)
|
||||||
|
private String dataSource;
|
||||||
|
@JSONField(ordinal = 4)
|
||||||
|
private String query;
|
||||||
|
@JSONField(ordinal = 5)
|
||||||
|
private long queryTimeout;
|
||||||
|
@JSONField(ordinal = 6)
|
||||||
|
private Boolean useEnvironment;
|
||||||
|
@JSONField(ordinal = 7)
|
||||||
|
private Assertions assertions;
|
||||||
|
@JSONField(ordinal = 8)
|
||||||
|
private Extract extract;
|
||||||
|
@JSONField(ordinal = 9)
|
||||||
|
private Boolean enable;
|
||||||
|
@JSONField(ordinal = 10)
|
||||||
|
private Boolean followRedirects;
|
||||||
|
@JSONField(ordinal = 11)
|
||||||
|
private JSR223PreProcessor jsr223PreProcessor;
|
||||||
|
@JSONField(ordinal = 12)
|
||||||
|
private JSR223PostProcessor jsr223PostProcessor;
|
||||||
|
}
|
|
@ -42,6 +42,7 @@
|
||||||
<el-radio-group v-model="type" @change="createRequest">
|
<el-radio-group v-model="type" @change="createRequest">
|
||||||
<el-radio :label="types.HTTP">HTTP</el-radio>
|
<el-radio :label="types.HTTP">HTTP</el-radio>
|
||||||
<el-radio :label="types.DUBBO">DUBBO</el-radio>
|
<el-radio :label="types.DUBBO">DUBBO</el-radio>
|
||||||
|
<el-radio :label="types.SQL">SQL</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<el-button slot="reference" :disabled="isReadOnly"
|
<el-button slot="reference" :disabled="isReadOnly"
|
||||||
class="request-create" type="primary" size="mini" icon="el-icon-plus" plain/>
|
class="request-create" type="primary" size="mini" icon="el-icon-plus" plain/>
|
||||||
|
|
|
@ -9,14 +9,15 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {JSR223Processor, Request, RequestFactory, Scenario} from "../../model/ScenarioModel";
|
import {JSR223Processor, Request, RequestFactory, Scenario} from "../../model/ScenarioModel";
|
||||||
import MsApiHttpRequestForm from "./ApiHttpRequestForm";
|
import MsApiHttpRequestForm from "./ApiHttpRequestForm";
|
||||||
import MsApiDubboRequestForm from "./ApiDubboRequestForm";
|
import MsApiDubboRequestForm from "./ApiDubboRequestForm";
|
||||||
import MsScenarioResults from "../../../report/components/ScenarioResults";
|
import MsScenarioResults from "../../../report/components/ScenarioResults";
|
||||||
import MsRequestResultTail from "../../../report/components/RequestResultTail";
|
import MsRequestResultTail from "../../../report/components/RequestResultTail";
|
||||||
|
import MsApiSqlRequestForm from "./ApiSqlRequestForm";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiRequestForm",
|
name: "MsApiRequestForm",
|
||||||
components: {MsRequestResultTail, MsScenarioResults, MsApiDubboRequestForm, MsApiHttpRequestForm},
|
components: {MsApiSqlRequestForm, MsRequestResultTail, MsScenarioResults, MsApiDubboRequestForm, MsApiHttpRequestForm},
|
||||||
props: {
|
props: {
|
||||||
scenario: Scenario,
|
scenario: Scenario,
|
||||||
request: Request,
|
request: Request,
|
||||||
|
@ -41,6 +42,9 @@ export default {
|
||||||
case RequestFactory.TYPES.DUBBO:
|
case RequestFactory.TYPES.DUBBO:
|
||||||
name = "MsApiDubboRequestForm";
|
name = "MsApiDubboRequestForm";
|
||||||
break;
|
break;
|
||||||
|
case RequestFactory.TYPES.SQL:
|
||||||
|
name = "MsApiSqlRequestForm";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
name = "MsApiHttpRequestForm";
|
name = "MsApiHttpRequestForm";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
<template>
|
||||||
|
<el-form :model="request" :rules="rules" ref="request" label-width="100px" :disabled="isReadOnly">
|
||||||
|
|
||||||
|
<el-form-item :label="$t('api_test.request.name')" prop="name">
|
||||||
|
<el-input v-model="request.name" maxlength="300" show-word-limit/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="'连接池'" prop="dataSource">
|
||||||
|
<el-select v-model="request.dataSource">
|
||||||
|
<el-option v-for="(item, index) in scenario.databaseConfigs" :key="index" :value="item.name" :label="item.name"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!--<el-form-item :label="'查询类型'" prop="protocol">-->
|
||||||
|
<!--<el-select v-model="request.queryType">-->
|
||||||
|
<!--<el-option label="dubbo://" :value="protocols.DUBBO"/>-->
|
||||||
|
<!--</el-select>-->
|
||||||
|
<!--</el-form-item>-->
|
||||||
|
|
||||||
|
<el-form-item :label="'超时时间'" prop="queryTimeout">
|
||||||
|
<el-input-number :disabled="isReadOnly" size="mini" v-model="request.queryTimeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0"/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small" type="primary" @click="runDebug">{{$t('api_test.request.debug')}}</el-button>
|
||||||
|
|
||||||
|
<el-tabs v-model="activeName">
|
||||||
|
<el-tab-pane :label="'sql脚本'" 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-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
|
||||||
|
<ms-api-assertions :is-read-only="isReadOnly" :assertions="request.assertions"/>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane :label="$t('api_test.request.extract.label')" name="extract">
|
||||||
|
<ms-api-extract :is-read-only="isReadOnly" :extract="request.extract"/>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane :label="$t('api_test.request.processor.pre_exec_script')" name="beanShellPreProcessor">
|
||||||
|
<ms-jsr233-processor :is-read-only="isReadOnly" :jsr223-processor="request.jsr223PreProcessor"/>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane :label="$t('api_test.request.processor.post_exec_script')" name="beanShellPostProcessor">
|
||||||
|
<ms-jsr233-processor :is-read-only="isReadOnly" :jsr223-processor="request.jsr223PostProcessor"/>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsApiKeyValue from "../ApiKeyValue";
|
||||||
|
import MsApiAssertions from "../assertion/ApiAssertions";
|
||||||
|
import {DubboRequest, Scenario, SqlRequest} from "../../model/ScenarioModel";
|
||||||
|
import MsApiExtract from "../extract/ApiExtract";
|
||||||
|
import ApiRequestMethodSelect from "../collapse/ApiRequestMethodSelect";
|
||||||
|
import MsDubboInterface from "@/business/components/api/test/components/request/dubbo/Interface";
|
||||||
|
import MsDubboRegistryCenter from "@/business/components/api/test/components/request/dubbo/RegistryCenter";
|
||||||
|
import MsDubboConfigCenter from "@/business/components/api/test/components/request/dubbo/ConfigCenter";
|
||||||
|
import MsDubboConsumerService from "@/business/components/api/test/components/request/dubbo/ConsumerAndService";
|
||||||
|
import MsJsr233Processor from "../processor/Jsr233Processor";
|
||||||
|
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiSqlRequestForm",
|
||||||
|
components: {
|
||||||
|
MsCodeEdit,
|
||||||
|
MsJsr233Processor,
|
||||||
|
MsDubboConsumerService,
|
||||||
|
MsDubboConfigCenter,
|
||||||
|
MsDubboRegistryCenter,
|
||||||
|
MsDubboInterface, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiKeyValue
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
request: SqlRequest,
|
||||||
|
scenario: Scenario,
|
||||||
|
isReadOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeName: "sql",
|
||||||
|
rules: {
|
||||||
|
name: [
|
||||||
|
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
|
||||||
|
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'},
|
||||||
|
],
|
||||||
|
dataSource: [
|
||||||
|
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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();
|
||||||
|
},
|
||||||
|
runDebug() {
|
||||||
|
this.$emit('runDebug');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.sql-content {
|
||||||
|
height: calc(100vh - 570px);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -8,7 +8,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="'数据库连接URL'" prop="dbUrl">
|
<el-form-item :label="'数据库连接URL'" prop="dbUrl">
|
||||||
<el-input v-model="config.dbUrl" maxlength="300" show-word-limit
|
<el-input v-model="config.dbUrl" maxlength="500" show-word-limit
|
||||||
:placeholder="$t('commons.input_content')"/>
|
:placeholder="$t('commons.input_content')"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="'密码'" prop="password">
|
<el-form-item :label="'密码'" prop="password">
|
||||||
<el-input v-model="config.password" maxlength="300" show-word-limit
|
<el-input v-model="config.password" maxlength="200" show-word-limit
|
||||||
:placeholder="$t('commons.input_content')"/>
|
:placeholder="$t('commons.input_content')"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -67,7 +67,6 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
drivers: DatabaseConfig.DRIVER_CLASS,
|
drivers: DatabaseConfig.DRIVER_CLASS,
|
||||||
// config: new DatabaseConfig(),
|
|
||||||
rules: {
|
rules: {
|
||||||
name: [
|
name: [
|
||||||
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
|
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
|
||||||
|
@ -95,7 +94,6 @@
|
||||||
this.$refs['databaseFrom'].validate((valid) => {
|
this.$refs['databaseFrom'].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$emit('save', this.config);
|
this.$emit('save', this.config);
|
||||||
// this.config = new DatabaseConfig();
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,6 +274,38 @@ export class DubboSample extends DefaultTestElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class JDBCSampler extends DefaultTestElement {
|
||||||
|
constructor(testName, request = {}) {
|
||||||
|
super('JDBCSampler', 'TestBeanGUI', 'JDBCSampler', testName);
|
||||||
|
|
||||||
|
this.stringProp("dataSource", request.dataSource);
|
||||||
|
this.stringProp("query", request.query);
|
||||||
|
this.stringProp("queryTimeout", request.queryTimeout);
|
||||||
|
this.stringProp("queryArguments");
|
||||||
|
this.stringProp("queryArgumentsTypes");
|
||||||
|
this.stringProp("resultSetMaxRows");
|
||||||
|
this.stringProp("resultVariable");
|
||||||
|
this.stringProp("variableNames");
|
||||||
|
this.stringProp("resultSetHandler", 'Store as String');
|
||||||
|
this.stringProp("queryType", 'Callable Statement');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <JDBCSampler guiclass="TestBeanGUI" testclass="JDBCSampler" testname="JDBC Request" enabled="true">
|
||||||
|
// <stringProp name="dataSource">test</stringProp>
|
||||||
|
// <stringProp name="query">select id from test_plan;
|
||||||
|
// select name from test_plan;
|
||||||
|
// </stringProp>
|
||||||
|
// <stringProp name="queryArguments"></stringProp>
|
||||||
|
// <stringProp name="queryArgumentsTypes"></stringProp>
|
||||||
|
// <stringProp name="queryTimeout"></stringProp>
|
||||||
|
// <stringProp name="queryType">Callable Statement</stringProp>
|
||||||
|
// <stringProp name="resultSetHandler">Store as String</stringProp>
|
||||||
|
// <stringProp name="resultSetMaxRows"></stringProp>
|
||||||
|
// <stringProp name="resultVariable"></stringProp>
|
||||||
|
// <stringProp name="variableNames"></stringProp>
|
||||||
|
// </JDBCSampler>
|
||||||
|
|
||||||
export class HTTPSamplerProxy extends DefaultTestElement {
|
export class HTTPSamplerProxy extends DefaultTestElement {
|
||||||
constructor(testName, options = {}) {
|
constructor(testName, options = {}) {
|
||||||
super('HTTPSamplerProxy', 'HttpTestSampleGui', 'HTTPSamplerProxy', testName);
|
super('HTTPSamplerProxy', 'HttpTestSampleGui', 'HTTPSamplerProxy', testName);
|
||||||
|
@ -515,6 +547,29 @@ export class DNSCacheManager extends DefaultTestElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class JDBCDataSource extends DefaultTestElement {
|
||||||
|
constructor(testName, datasource) {
|
||||||
|
super('JDBCDataSource', 'TestBeanGUI', 'JDBCDataSource', testName);
|
||||||
|
|
||||||
|
this.boolProp('autocommit', true);
|
||||||
|
this.boolProp('keepAlive', true);
|
||||||
|
this.boolProp('preinit', false);
|
||||||
|
this.stringProp('dataSource', datasource.name);
|
||||||
|
this.stringProp('dbUrl', datasource.dbUrl);
|
||||||
|
this.stringProp('driver', datasource.driver);
|
||||||
|
this.stringProp('username', datasource.username);
|
||||||
|
this.stringProp('password', datasource.password);
|
||||||
|
this.stringProp('poolMax', datasource.poolMax);
|
||||||
|
this.stringProp('timeout', datasource.timeout);
|
||||||
|
this.stringProp('connectionAge', '5000');
|
||||||
|
this.stringProp('trimInterval', '60000');
|
||||||
|
this.stringProp('transactionIsolation', 'DEFAULT');
|
||||||
|
this.stringProp('checkQuery');
|
||||||
|
this.stringProp('initQuery');
|
||||||
|
this.stringProp('connectionProperties');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Arguments extends DefaultTestElement {
|
export class Arguments extends DefaultTestElement {
|
||||||
constructor(testName, args) {
|
constructor(testName, args) {
|
||||||
super('Arguments', 'ArgumentsPanel', 'Arguments', testName);
|
super('Arguments', 'ArgumentsPanel', 'Arguments', testName);
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
HashTree,
|
HashTree,
|
||||||
HeaderManager,
|
HeaderManager,
|
||||||
HTTPSamplerArguments, HTTPsamplerFiles,
|
HTTPSamplerArguments, HTTPsamplerFiles,
|
||||||
HTTPSamplerProxy,
|
HTTPSamplerProxy, JDBCDataSource, JDBCSampler,
|
||||||
JSONPathAssertion,
|
JSONPathAssertion,
|
||||||
JSONPostProcessor, JSR223PostProcessor, JSR223PreProcessor,
|
JSONPostProcessor, JSR223PostProcessor, JSR223PreProcessor,
|
||||||
RegexExtractor,
|
RegexExtractor,
|
||||||
|
@ -211,7 +211,7 @@ export class Scenario extends BaseConfig {
|
||||||
this.environment = undefined;
|
this.environment = undefined;
|
||||||
this.enableCookieShare = false;
|
this.enableCookieShare = false;
|
||||||
this.enable = true;
|
this.enable = true;
|
||||||
this.databaseConfigs = undefined;
|
this.databaseConfigs = [];
|
||||||
|
|
||||||
this.set(options);
|
this.set(options);
|
||||||
this.sets({variables: KeyValue, headers: KeyValue, requests: RequestFactory, databaseConfigs: DatabaseConfig}, options);
|
this.sets({variables: KeyValue, headers: KeyValue, requests: RequestFactory, databaseConfigs: DatabaseConfig}, options);
|
||||||
|
@ -273,6 +273,7 @@ export class RequestFactory {
|
||||||
static TYPES = {
|
static TYPES = {
|
||||||
HTTP: "HTTP",
|
HTTP: "HTTP",
|
||||||
DUBBO: "DUBBO",
|
DUBBO: "DUBBO",
|
||||||
|
SQL: "SQL",
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
|
@ -280,6 +281,8 @@ export class RequestFactory {
|
||||||
switch (options.type) {
|
switch (options.type) {
|
||||||
case RequestFactory.TYPES.DUBBO:
|
case RequestFactory.TYPES.DUBBO:
|
||||||
return new DubboRequest(options);
|
return new DubboRequest(options);
|
||||||
|
case RequestFactory.TYPES.SQL:
|
||||||
|
return new SqlRequest(options);
|
||||||
default:
|
default:
|
||||||
return new HttpRequest(options);
|
return new HttpRequest(options);
|
||||||
}
|
}
|
||||||
|
@ -460,6 +463,60 @@ export class DubboRequest extends Request {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SqlRequest extends Request {
|
||||||
|
|
||||||
|
constructor(options = {}) {
|
||||||
|
super(RequestFactory.TYPES.SQL);
|
||||||
|
this.id = options.id || uuid();
|
||||||
|
this.name = options.name;
|
||||||
|
this.dataSource = options.dataSource;
|
||||||
|
this.query = options.query;
|
||||||
|
// this.queryType = options.queryType;
|
||||||
|
this.queryTimeout = options.queryTimeout;
|
||||||
|
this.enable = options.enable === undefined ? true : options.enable;
|
||||||
|
this.assertions = new Assertions(options.assertions);
|
||||||
|
this.extract = new Extract(options.extract);
|
||||||
|
this.jsr223PreProcessor = new JSR223Processor(options.jsr223PreProcessor);
|
||||||
|
this.jsr223PostProcessor = new JSR223Processor(options.jsr223PostProcessor);
|
||||||
|
|
||||||
|
this.sets({args: KeyValue, attachmentArgs: KeyValue}, options);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
if (this.enable) {
|
||||||
|
if (!this.name) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
info: 'name'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.dataSource) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
info: 'dataSource'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
isValid: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showType() {
|
||||||
|
return "SQL";
|
||||||
|
}
|
||||||
|
|
||||||
|
showMethod() {
|
||||||
|
return "SQL";
|
||||||
|
}
|
||||||
|
|
||||||
|
clone() {
|
||||||
|
return new SqlRequest(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class ConfigCenter extends BaseConfig {
|
export class ConfigCenter extends BaseConfig {
|
||||||
static PROTOCOLS = ["zookeeper", "nacos", "apollo"];
|
static PROTOCOLS = ["zookeeper", "nacos", "apollo"];
|
||||||
|
|
||||||
|
@ -502,24 +559,6 @@ export class DatabaseConfig extends BaseConfig {
|
||||||
// options.id = options.id || uuid();
|
// options.id = options.id || uuid();
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
// <JDBCDataSource guiclass="TestBeanGUI" testclass="JDBCDataSource" testname="JDBC Connection Configurationqqq" enabled="true">
|
|
||||||
// <boolProp name="autocommit">true</boolProp>
|
|
||||||
// <stringProp name="checkQuery"></stringProp>
|
|
||||||
// <stringProp name="connectionAge">5000</stringProp>
|
|
||||||
// <stringProp name="connectionProperties"></stringProp>
|
|
||||||
// <stringProp name="dataSource">test</stringProp>
|
|
||||||
// <stringProp name="dbUrl">jdbc:mysql://localhost:3306/metersphere?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true</stringProp>
|
|
||||||
// <stringProp name="driver">com.mysql.jdbc.Driver</stringProp>
|
|
||||||
// <stringProp name="initQuery"></stringProp>
|
|
||||||
// <boolProp name="keepAlive">true</boolProp>
|
|
||||||
// <stringProp name="password">root</stringProp>
|
|
||||||
// <stringProp name="poolMax">10</stringProp>
|
|
||||||
// <boolProp name="preinit">false</boolProp>
|
|
||||||
// <stringProp name="timeout">10000</stringProp>
|
|
||||||
// <stringProp name="transactionIsolation">DEFAULT</stringProp>
|
|
||||||
// <stringProp name="trimInterval">60000</stringProp>
|
|
||||||
// <stringProp name="username">root</stringProp>
|
|
||||||
// </JDBCDataSource>
|
|
||||||
|
|
||||||
isValid() {
|
isValid() {
|
||||||
return !!this.name || !!this.poolMax || !!this.timeout || !!this.driver || !!this.dbUrl || !!this.username || !!this.password;
|
return !!this.name || !!this.poolMax || !!this.timeout || !!this.driver || !!this.dbUrl || !!this.username || !!this.password;
|
||||||
|
@ -929,6 +968,8 @@ class JMXGenerator {
|
||||||
// 放在计划或线程组中,不建议放具体某个请求中
|
// 放在计划或线程组中,不建议放具体某个请求中
|
||||||
this.addDNSCacheManager(threadGroup, scenario.requests[0]);
|
this.addDNSCacheManager(threadGroup, scenario.requests[0]);
|
||||||
|
|
||||||
|
this.addJDBCDataSource(threadGroup, scenario);
|
||||||
|
|
||||||
scenario.requests.forEach(request => {
|
scenario.requests.forEach(request => {
|
||||||
if (request.enable) {
|
if (request.enable) {
|
||||||
if (!request.isValid()) return;
|
if (!request.isValid()) return;
|
||||||
|
@ -936,9 +977,7 @@ class JMXGenerator {
|
||||||
|
|
||||||
if (request instanceof DubboRequest) {
|
if (request instanceof DubboRequest) {
|
||||||
sampler = new DubboSample(request.name || "", new JMXDubboRequest(request, scenario.dubboConfig));
|
sampler = new DubboSample(request.name || "", new JMXDubboRequest(request, scenario.dubboConfig));
|
||||||
}
|
} else if (request instanceof HttpRequest) {
|
||||||
|
|
||||||
if (request instanceof HttpRequest) {
|
|
||||||
sampler = new HTTPSamplerProxy(request.name || "", new JMXHttpRequest(request, scenario.environment));
|
sampler = new HTTPSamplerProxy(request.name || "", new JMXHttpRequest(request, scenario.environment));
|
||||||
this.addRequestHeader(sampler, request);
|
this.addRequestHeader(sampler, request);
|
||||||
if (request.method.toUpperCase() === 'GET') {
|
if (request.method.toUpperCase() === 'GET') {
|
||||||
|
@ -946,6 +985,8 @@ class JMXGenerator {
|
||||||
} else {
|
} else {
|
||||||
this.addRequestBody(sampler, request, testId);
|
this.addRequestBody(sampler, request, testId);
|
||||||
}
|
}
|
||||||
|
} else if (request instanceof SqlRequest) {
|
||||||
|
sampler = new JDBCSampler(request.name || "", request);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addRequestExtractor(sampler, request);
|
this.addRequestExtractor(sampler, request);
|
||||||
|
@ -1009,6 +1050,13 @@ class JMXGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addJDBCDataSource(threadGroup, scenario) {
|
||||||
|
scenario.databaseConfigs.forEach(config => {
|
||||||
|
let name = config.name + "JDBCDataSource";
|
||||||
|
threadGroup.put(new JDBCDataSource(name, config));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
addScenarioHeaders(threadGroup, scenario) {
|
addScenarioHeaders(threadGroup, scenario) {
|
||||||
let environment = scenario.environment;
|
let environment = scenario.environment;
|
||||||
if (environment) {
|
if (environment) {
|
||||||
|
|
Loading…
Reference in New Issue