feat(插件管理): 插件管理增加条件控制和jmeter菜单权限一致

This commit is contained in:
fit2-zhao 2021-09-09 15:53:01 +08:00 committed by fit2-zhao
parent f62bf59c45
commit 2c321c3422
19 changed files with 415 additions and 157 deletions

View File

@ -444,7 +444,7 @@
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>metersphere-plugin-core</artifactId>
<version>1.0</version>
<version>1.0.1</version>
</dependency>
<!--随机数据生成API-->
<dependency>

View File

@ -1,5 +0,0 @@
package io.metersphere.api.jmeter;
public class MenuFactory {
}

View File

@ -13,6 +13,8 @@ public class Plugin implements Serializable {
private String scriptId;
private String jmeterClazz;
private String clazzName;
private String sourcePath;

View File

@ -384,6 +384,76 @@ public class PluginExample {
return (Criteria) this;
}
public Criteria andJmeterClazzIsNull() {
addCriterion("jmeter_clazz is null");
return (Criteria) this;
}
public Criteria andJmeterClazzIsNotNull() {
addCriterion("jmeter_clazz is not null");
return (Criteria) this;
}
public Criteria andJmeterClazzEqualTo(String value) {
addCriterion("jmeter_clazz =", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotEqualTo(String value) {
addCriterion("jmeter_clazz <>", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzGreaterThan(String value) {
addCriterion("jmeter_clazz >", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzGreaterThanOrEqualTo(String value) {
addCriterion("jmeter_clazz >=", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLessThan(String value) {
addCriterion("jmeter_clazz <", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLessThanOrEqualTo(String value) {
addCriterion("jmeter_clazz <=", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLike(String value) {
addCriterion("jmeter_clazz like", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotLike(String value) {
addCriterion("jmeter_clazz not like", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzIn(List<String> values) {
addCriterion("jmeter_clazz in", values, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotIn(List<String> values) {
addCriterion("jmeter_clazz not in", values, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzBetween(String value1, String value2) {
addCriterion("jmeter_clazz between", value1, value2, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotBetween(String value1, String value2) {
addCriterion("jmeter_clazz not between", value1, value2, "jmeterClazz");
return (Criteria) this;
}
public Criteria andClazzNameIsNull() {
addCriterion("clazz_name is null");
return (Criteria) this;

View File

@ -6,6 +6,7 @@
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="plugin_id" jdbcType="VARCHAR" property="pluginId" />
<result column="script_id" jdbcType="VARCHAR" property="scriptId" />
<result column="jmeter_clazz" jdbcType="VARCHAR" property="jmeterClazz" />
<result column="clazz_name" jdbcType="VARCHAR" property="clazzName" />
<result column="source_path" jdbcType="VARCHAR" property="sourcePath" />
<result column="source_name" jdbcType="VARCHAR" property="sourceName" />
@ -77,8 +78,8 @@
</where>
</sql>
<sql id="Base_Column_List">
id, `name`, plugin_id, script_id, clazz_name, source_path, source_name, exec_entry,
create_time, update_time, create_user_id
id, `name`, plugin_id, script_id, jmeter_clazz, clazz_name, source_path, source_name,
exec_entry, create_time, update_time, create_user_id
</sql>
<sql id="Blob_Column_List">
form_option, form_script
@ -133,15 +134,15 @@
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
insert into plugin (id, `name`, plugin_id,
script_id, clazz_name, source_path,
source_name, exec_entry, create_time,
update_time, create_user_id, form_option,
form_script)
script_id, jmeter_clazz, clazz_name,
source_path, source_name, exec_entry,
create_time, update_time, create_user_id,
form_option, form_script)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{pluginId,jdbcType=VARCHAR},
#{scriptId,jdbcType=VARCHAR}, #{clazzName,jdbcType=VARCHAR}, #{sourcePath,jdbcType=VARCHAR},
#{sourceName,jdbcType=VARCHAR}, #{execEntry,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{createUserId,jdbcType=VARCHAR}, #{formOption,jdbcType=LONGVARCHAR},
#{formScript,jdbcType=LONGVARCHAR})
#{scriptId,jdbcType=VARCHAR}, #{jmeterClazz,jdbcType=VARCHAR}, #{clazzName,jdbcType=VARCHAR},
#{sourcePath,jdbcType=VARCHAR}, #{sourceName,jdbcType=VARCHAR}, #{execEntry,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUserId,jdbcType=VARCHAR},
#{formOption,jdbcType=LONGVARCHAR}, #{formScript,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
insert into plugin
@ -158,6 +159,9 @@
<if test="scriptId != null">
script_id,
</if>
<if test="jmeterClazz != null">
jmeter_clazz,
</if>
<if test="clazzName != null">
clazz_name,
</if>
@ -199,6 +203,9 @@
<if test="scriptId != null">
#{scriptId,jdbcType=VARCHAR},
</if>
<if test="jmeterClazz != null">
#{jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="clazzName != null">
#{clazzName,jdbcType=VARCHAR},
</if>
@ -249,6 +256,9 @@
<if test="record.scriptId != null">
script_id = #{record.scriptId,jdbcType=VARCHAR},
</if>
<if test="record.jmeterClazz != null">
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="record.clazzName != null">
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
</if>
@ -287,6 +297,7 @@
`name` = #{record.name,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
script_id = #{record.scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
source_path = #{record.sourcePath,jdbcType=VARCHAR},
source_name = #{record.sourceName,jdbcType=VARCHAR},
@ -306,6 +317,7 @@
`name` = #{record.name,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
script_id = #{record.scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
source_path = #{record.sourcePath,jdbcType=VARCHAR},
source_name = #{record.sourceName,jdbcType=VARCHAR},
@ -329,6 +341,9 @@
<if test="scriptId != null">
script_id = #{scriptId,jdbcType=VARCHAR},
</if>
<if test="jmeterClazz != null">
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="clazzName != null">
clazz_name = #{clazzName,jdbcType=VARCHAR},
</if>
@ -364,6 +379,7 @@
set `name` = #{name,jdbcType=VARCHAR},
plugin_id = #{pluginId,jdbcType=VARCHAR},
script_id = #{scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{clazzName,jdbcType=VARCHAR},
source_path = #{sourcePath,jdbcType=VARCHAR},
source_name = #{sourceName,jdbcType=VARCHAR},
@ -380,6 +396,7 @@
set `name` = #{name,jdbcType=VARCHAR},
plugin_id = #{pluginId,jdbcType=VARCHAR},
script_id = #{scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{clazzName,jdbcType=VARCHAR},
source_path = #{sourcePath,jdbcType=VARCHAR},
source_name = #{sourceName,jdbcType=VARCHAR},

View File

@ -70,6 +70,7 @@ public class PluginService {
plugin.setFormScript(item.getFormScript());
plugin.setClazzName(item.getClazzName());
plugin.setSourceName(name);
plugin.setJmeterClazz(item.getJmeterClazz());
plugin.setExecEntry(resource.getEntry());
plugin.setCreateUserId(SessionUtils.getUserId());
pluginMapper.insert(plugin);

View File

@ -67,7 +67,7 @@ import MsApiReportExport from "./ApiReportExport";
import MsApiReportViewHeader from "./ApiReportViewHeader";
import {RequestFactory} from "../../definition/model/ApiTestModel";
import {windowPrint, getCurrentProjectID, getUUID} from "@/common/js/utils";
import {ELEMENTS} from "../scenario/Setting";
import {STEP} from "../scenario/Setting";
import {scenario} from "@/business/components/track/plan/event-bus";
export default {
@ -100,7 +100,8 @@ export default {
scenarioMap: new Map,
exportFlag: false,
messageWebSocket: {},
websocket: {}
websocket: {},
stepFilter: this.stepFilter,
}
},
activated() {
@ -221,13 +222,13 @@ export default {
let name = item.name ? item.name : this.getType(item.type);
let obj = {resId: item.resourceId + "_" + item.parentIndex, index: Number(item.index), label: name, value: {name: name, responseResult: {}, unexecute: true, testing: false}, children: [], unsolicited: true};
tree.children.push(obj);
if (ELEMENTS.get("AllSamplerProxy").indexOf(item.type) != -1) {
if (this.stepFilter.get("AllSamplerProxy").indexOf(item.type) !== -1) {
obj.unsolicited = false;
obj.type = item.type;
} else if (item.type === 'scenario') {
this.content.scenarioTotal += 1;
}
if (item.hashTree && item.hashTree.length > 0 && ELEMENTS.get("AllSamplerProxy").indexOf(item.type) === -1) {
if (item.hashTree && item.hashTree.length > 0 && this.stepFilter && this.stepFilter.get("AllSamplerProxy").indexOf(item.type) === -1) {
this.formatContent(item.hashTree, obj, item.parentIndex);
}
}

View File

@ -325,7 +325,7 @@
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
import {buttons, setComponent} from './menu/Menu';
import {parseEnvironment} from "../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS,TYPE_TO_C} from "./Setting";
import {ELEMENT_TYPE, STEP, TYPE_TO_C, PLUGIN_ELEMENTS} from "./Setting";
import {
getUUID,
objToStrMap,
@ -448,7 +448,8 @@ export default {
message: "",
websocket: {},
messageWebSocket: {},
buttonData: []
buttonData: [],
stepFilter: new STEP,
}
},
created() {
@ -457,7 +458,9 @@ export default {
}
this.debug = false;
this.debugLoading = false;
this.operatingElements = ELEMENTS.get("ALL");
if (this.stepFilter) {
this.operatingElements = this.stepFilter.get("ALL");
}
this.getWsProjects();
this.getMaintainerOptions();
this.getApiScenario();
@ -487,7 +490,7 @@ export default {
data.forEach(item => {
let plugin = {
title: item.name,
show: this.showButton(item.name),
show: this.showButton(item.jmeterClazz),
titleColor: "#555855",
titleBgColor: "#F4F4FF",
icon: "colorize",
@ -495,7 +498,9 @@ export default {
this.addComponent(item.name, item)
}
}
this.buttonData.push(plugin);
if (this.operatingElements && this.operatingElements.includes(item.jmeterClazz)) {
this.buttonData.push(plugin);
}
});
}
});
@ -847,18 +852,19 @@ export default {
setComponent(type, this, plugin);
},
nodeClick(data, node) {
if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled) {
this.operatingElements = ELEMENTS.get(data.type);
if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled && this.stepFilter) {
this.operatingElements = this.stepFilter.get(data.type);
} else {
this.operatingElements = [];
}
if (!this.operatingElements) {
this.operatingElements = ELEMENTS.get("ALL");
if (!this.operatingElements && this.stepFilter) {
this.operatingElements = this.stepFilter.get("ALL");
}
this.selectedTreeNode = data;
this.selectedNode = node;
this.$store.state.selectStep = data;
this.buttonData = buttons(this);
this.initPlugins();
},
suggestClick(node) {
this.response = {};
@ -869,7 +875,7 @@ export default {
showAll() {
//
if (!this.customizeVisible && !this.isBtnHide) {
this.operatingElements = ELEMENTS.get("ALL");
this.operatingElements = this.stepFilter.get("ALL");
this.selectedTreeNode = undefined;
this.$store.state.selectStep = undefined;
}
@ -1144,10 +1150,12 @@ export default {
this.getEnvironments();
},
allowDrop(draggingNode, dropNode, dropType) {
//
if (dropType != "inner") {
return true;
} else if (dropType === "inner" && dropNode.data.referenced !== 'REF' && dropNode.data.referenced !== 'Deleted'
&& ELEMENTS.get(dropNode.data.type) && ELEMENTS.get(dropNode.data.type).indexOf(draggingNode.data.type) != -1 && !draggingNode.data.disabled) {
&& (this.stepFilter.get(dropNode.data.type) && this.stepFilter.get(dropNode.data.type).indexOf(draggingNode.data.type) != -1)
&& !draggingNode.data.disabled) {
return true;
}
return false;
@ -1177,7 +1185,7 @@ export default {
this.$refs['currentScenario'].validate((valid) => {
if (valid) {
this.setParameter();
saveScenario(this.path, this.currentScenario, this.scenarioDefinition, this,(response) => {
saveScenario(this.path, this.currentScenario, this.scenarioDefinition, this, (response) => {
this.$success(this.$t('commons.save_success'));
this.path = "/api/automation/update";
this.$store.state.pluginFiles = [];

View File

@ -1,28 +0,0 @@
export const ELEMENTS = new Map([
['menu_post_processors', ['HtmlExtractor', 'JMESPathExtractor', 'JSONPostProcessor', 'RegexExtractor', 'BoundaryExtractor', 'JSR223PostProcessor', 'Separator', 'JDBCPostProcessor', 'XPath2Extractor', 'XPathExtractor', 'ResultAction', 'DebugPostProcessor', 'BeanShellPostProcessor']],
['menu_assertions', ['Assertion', 'JSONPathAssertion', 'SizeAssertion', 'JSR223Assertion', 'XPath2Assertion', 'Separator', 'HTMLAssertion', 'JMESPathAssertion', 'MD5HexAssertion', 'SMIMEAssertion', 'XMLSchemaAssertion', 'XMLAssertion', 'XPathAssertion', 'DurationAssertion', 'CompareAssertion', 'BeanShellAssertion']],
['menu_listener', ['ViewResultsFullVisualizer', 'SummaryReport', 'StatVisualizer', 'BackendListener', 'Separator', 'JSR223Listener', 'ResultSaver', 'RespTimeGraphVisualizer', 'GraphVisualizer', 'AssertionVisualizer', 'ComparisonVisualizer', 'StatGraphVisualizer', 'Summariser', 'TableVisualizer', 'SimpleDataWriter', 'MailerVisualizer', 'BeanShellListener']],
['menu_pre_processors', ['JSR223PreProcessor', 'UserParameters', 'Separator', 'AnchorModifier', 'URLRewritingModifier', 'JDBCPreProcessor', 'SampleTimeout', 'RegExUserParameters', 'BeanShellPreProcessor']],
['menu_logic_controller', ['IfControllerPanel', 'TransactionController', 'LoopControlPanel', 'WhileController', 'Separator', 'ForeachControlPanel', 'IncludeController', 'RunTime', 'CriticalSectionController', 'InterleaveControl', 'OnceOnlyController', 'RecordController', 'LogicController', 'RandomControl', 'RandomOrderController', 'ThroughputController', 'SwitchController', 'ModuleController']],
['menu_fragments', ['TestFragmentController']],
['menu_non_test_elements', ['ProxyControl', 'HttpMirrorControl', 'GenerateTree', 'PropertyControl']],
['menu_generative_controller', ['HttpTestSample', 'TestAction', 'DebugSampler', 'JSR223Sampler', 'Separator', 'AjpSampler', 'AccessLogSampler', 'BeanShellSampler', 'BoltSampler', 'FtpTestSampler', 'GraphQLHTTPSampler', 'JDBCSampler', 'JMSPublisher', 'JMSSampler', 'JMSSubscriber', 'JUnitTestSampler', 'JavaTestSampler', 'LdapExtTestSampler', 'LdapTestSampler', 'SystemSampler', 'SmtpSampler', 'TCPSampler', 'MailReaderSampler']],
['menu_threads', ['SetupThreadGroup', 'PostThreadGroup', 'ThreadGroup']],
['menu_timer', ['ConstantTimer', 'UniformRandomTimer', 'PreciseThroughputTimer', 'ConstantThroughputTimer', 'Separator', 'JSR223Timer', 'SyncTimer', 'PoissonRandomTimer', 'GaussianRandomTimer', 'BeanShellTimer']],
['menu_config_element', ['CSVDataSet', 'HeaderPanel', 'CookiePanel', 'CacheManager', 'HttpDefaults', 'Separator', 'BoltConnectionElement', 'DNSCachePanel', 'FtpConfig', 'AuthPanel', 'DataSourceElement', 'JavaConfig', 'LdapExtConfig', 'LdapConfig', 'TCPConfig', 'KeystoreConfig', 'ArgumentsPanel', 'LoginConfig', 'SimpleConfig', 'CounterConfig', 'RandomVariableConfig']],
])
export function getDefaultSamplerMenu() {
let array = [];
array.push(ELEMENTS.get('menu_assertions'));
array.push(ELEMENTS.get('menu_timer'));
array.push(ELEMENTS.get('menu_pre_processors'));
array.push(ELEMENTS.get('menu_post_processors'));
array.push(ELEMENTS.get('menu_config_element'));
array.push(ELEMENTS.get('menu_listener'));
return array;
}
export function getLogicMenu() {
return ELEMENTS.values();
}

View File

@ -1,28 +1,32 @@
export const ELEMENTS = new Map([
['ALL', ["Plugin","scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "IfController", "TransactionController", "LoopController", "ConstantTimer", "JSR223Processor", "CustomizeReq"]],
['scenario', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "CASE", "OT_IMPORT", "IfController", "ConstantTimer", "JSR223Processor", "CustomizeReq"]],
['HTTPSamplerProxy', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['DubboSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['JDBCSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['TCPSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['OT_IMPORT', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['IfController', ["IfController", "LoopController", "TransactionController", "scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract", "CustomizeReq"]],
['TransactionController', ["TransactionController", "scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract", "CustomizeReq"]],
['LoopController', ["IfController", "TransactionController", "scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract", "CustomizeReq"]],
['ConstantTimer', []],
['JSR223Processor', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
['JSR223PreProcessor', []],
['JSR223PostProcessor', []],
['JDBCPreProcessor', []],
['JDBCPostProcessor', []],
['Assertions', []],
['Extract', []],
['JmeterElement', []],
['CustomizeReq', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", "JDBCPostProcessor", "JDBCPreProcessor", "Assertions", "Extract"]],
['MaxSamplerProxy', ["JSR223PreProcessor", "JSR223PostProcessor", "JDBCPreProcessor", "JDBCPostProcessor", "Assertions", "Extract"]],
['AllSamplerProxy', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler","Sampler"]],
['AllCanExecType', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "JSR223Processor"]]
])
export function STEP() {
let map = new Map([
['ALL', init()],
['scenario', init()],
['HTTPSamplerProxy', getDefaultSamplerMenu()],
['DubboSampler', getDefaultSamplerMenu()],
['JDBCSampler', getDefaultSamplerMenu()],
['TCPSampler', getDefaultSamplerMenu()],
['OT_IMPORT', getDefaultSamplerMenu()],
['AbstractSampler', getDefaultSamplerMenu()],
['IfController', getAll()],
['TransactionController', getAll()],
['LoopController', getAll()],
['ConstantTimer', []],
['JSR223Processor', getDefaultSamplerMenu()],
['JSR223PreProcessor', []],
['JSR223PostProcessor', []],
['JDBCPreProcessor', []],
['JDBCPostProcessor', []],
['Assertions', []],
['Extract', []],
['JmeterElement', []],
['CustomizeReq', getDefaultSamplerMenu()],
['MaxSamplerProxy', getDefaultSamplerMenu()],
['GenericController', getAll()],
['AllSamplerProxy', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "Sampler", "AbstractSampler"]],
['AllCanExecType', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "JSR223Processor", "AbstractSampler"]]]);
return map
}
export const ELEMENT_TYPE = {
scenario: "scenario",
@ -67,3 +71,46 @@ export const TYPE_TO_C = new Map([
['DebugSampler', "io.metersphere.api.dto.definition.request.sampler.MsDebugSampler"],
])
export const PLUGIN_ELEMENTS = new Map([
['menu_post_processors', ['HtmlExtractor', 'JMESPathExtractor', 'JSONPostProcessor', 'RegexExtractor', 'BoundaryExtractor', 'JSR223PostProcessor', 'Separator', 'JDBCPostProcessor', 'XPath2Extractor', 'XPathExtractor', 'ResultAction', 'DebugPostProcessor', 'BeanShellPostProcessor']],
['menu_assertions', ["Assertions", "Extract", 'Assertion', 'JSONPathAssertion', 'SizeAssertion', 'JSR223Assertion', 'XPath2Assertion', 'Separator', 'HTMLAssertion', 'JMESPathAssertion', 'MD5HexAssertion', 'SMIMEAssertion', 'XMLSchemaAssertion', 'XMLAssertion', 'XPathAssertion', 'DurationAssertion', 'CompareAssertion', 'BeanShellAssertion']],
['menu_listener', ['AbstractVisualizer', 'AbstractListener', 'ViewResultsFullVisualizer', 'SummaryReport', 'StatVisualizer', 'BackendListener', 'Separator', 'JSR223Listener', 'ResultSaver', 'RespTimeGraphVisualizer', 'GraphVisualizer', 'AssertionVisualizer', 'ComparisonVisualizer', 'StatGraphVisualizer', 'Summariser', 'TableVisualizer', 'SimpleDataWriter', 'MailerVisualizer', 'BeanShellListener']],
['menu_pre_processors', ['AbstractPostProcessor', 'JSR223PreProcessor', 'UserParameters', 'Separator', 'AnchorModifier', 'URLRewritingModifier', 'JDBCPreProcessor', 'SampleTimeout', 'RegExUserParameters', 'BeanShellPreProcessor']],
['menu_logic_controller', ['GenericController', "IfController", "LoopController", 'IfControllerPanel', 'TransactionController', 'LoopControlPanel', 'WhileController', 'Separator', 'ForeachControlPanel', 'IncludeController', 'RunTime', 'CriticalSectionController', 'InterleaveControl', 'OnceOnlyController', 'RecordController', 'LogicController', 'RandomControl', 'RandomOrderController', 'ThroughputController', 'SwitchController', 'ModuleController']],
['menu_fragments', ['TestFragmentController']],
['menu_non_test_elements', ['ProxyControl', 'HttpMirrorControl', 'GenerateTree', 'PropertyControl']],
['menu_generative_controller', ['AbstractSampler', 'CustomizeReq', 'HttpTestSample', 'TestAction', 'DebugSampler', 'JSR223Sampler', 'Separator', 'AjpSampler', 'AccessLogSampler', 'BeanShellSampler', 'BoltSampler', 'FtpTestSampler', 'GraphQLHTTPSampler', 'JDBCSampler', 'JMSPublisher', 'JMSSampler', 'JMSSubscriber', 'JUnitTestSampler', 'JavaTestSampler', 'LdapExtTestSampler', 'LdapTestSampler', 'SystemSampler', 'SmtpSampler', 'TCPSampler', 'MailReaderSampler']],
['menu_threads', ['SetupThreadGroup', 'PostThreadGroup', 'ThreadGroup']],
['menu_timer', ['ConstantTimer', 'UniformRandomTimer', 'PreciseThroughputTimer', 'ConstantThroughputTimer', 'Separator', 'JSR223Timer', 'SyncTimer', 'PoissonRandomTimer', 'GaussianRandomTimer', 'BeanShellTimer']],
['menu_config_element', ['CSVDataSet', 'HeaderPanel', 'CookiePanel', 'CacheManager', 'HttpDefaults', 'Separator', 'BoltConnectionElement', 'DNSCachePanel', 'FtpConfig', 'AuthPanel', 'DataSourceElement', 'JavaConfig', 'LdapExtConfig', 'LdapConfig', 'TCPConfig', 'KeystoreConfig', 'ArgumentsPanel', 'LoginConfig', 'SimpleConfig', 'CounterConfig', 'RandomVariableConfig']],
])
export function getDefaultSamplerMenu() {
let array = [];
array = array.concat(PLUGIN_ELEMENTS.get('menu_assertions'));
array = array.concat(PLUGIN_ELEMENTS.get('menu_timer'));
array = array.concat(PLUGIN_ELEMENTS.get('menu_pre_processors'));
array = array.concat(PLUGIN_ELEMENTS.get('menu_post_processors'));
array = array.concat(PLUGIN_ELEMENTS.get('menu_config_element'));
array = array.concat(PLUGIN_ELEMENTS.get('menu_listener'));
return array;
}
export function init() {
let allArray = [];
allArray = allArray.concat(PLUGIN_ELEMENTS.get('menu_generative_controller'));
allArray = allArray.concat(PLUGIN_ELEMENTS.get('menu_logic_controller'));
allArray = allArray.concat(["scenario", "ConstantTimer", "JSR223Processor"]);
return allArray;
}
export function getAll() {
let allArray = [];
allArray = allArray.concat(getDefaultSamplerMenu());
allArray = allArray.concat(PLUGIN_ELEMENTS.get('menu_logic_controller'));
allArray = allArray.concat(PLUGIN_ELEMENTS.get('menu_non_test_elements'));
allArray = allArray.concat(PLUGIN_ELEMENTS.get('menu_generative_controller'));
allArray = allArray.concat(PLUGIN_ELEMENTS.get('menu_threads'));
return allArray;
}

View File

@ -64,7 +64,7 @@
<script>
import StepExtendBtns from "../component/StepExtendBtns";
import {ELEMENTS} from "../Setting";
import {STEP} from "../Setting";
export default {
name: "ApiBaseComponent",
@ -73,6 +73,7 @@ export default {
return {
isShowInput: false,
colorStyle: "",
stepFilter: new STEP,
}
},
props: {
@ -135,7 +136,7 @@ export default {
this.$refs.nameEdit.focus();
});
}
if (this.data && ELEMENTS.get("AllSamplerProxy").indexOf(this.data.type) != -1) {
if (this.data && this.stepFilter.get("AllSamplerProxy").indexOf(this.data.type) != -1) {
if (!this.data.method) {
this.data.method = this.data.protocol;
}

View File

@ -430,7 +430,6 @@ export default {
this.request.active = true;
this.loading = true;
this.runData = [];
this.runData.projectId = this.request.projectId;
this.request.useEnvironment = this.currentEnvironmentId;
this.request.customizeReq = this.isCustomizeReq;
let debugData = {
@ -447,7 +446,6 @@ export default {
stop() {
let url = "/api/automation/stop/" + this.reportId;
this.$get(url, () => {
this.runLoading = false;
this.loading = false;
this.$success(this.$t('report.test_stop_success'));
});

View File

@ -89,7 +89,7 @@ import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent";
import MsRun from "../DebugRun";
import {getUUID} from "@/common/js/utils";
import {ELEMENT_TYPE, ELEMENTS} from "../Setting";
import {ELEMENT_TYPE, STEP} from "../Setting";
export default {
name: "MsLoopController",
@ -158,6 +158,7 @@ export default {
label: "commons.adv_search.operators.is_not_empty",
value: "is not empty",
},
stepFilter: new STEP,
},
};
},
@ -206,7 +207,7 @@ export default {
if (this.controller.hashTree && this.controller.hashTree.length === 1 && this.controller.hashTree[0].hashTree && this.controller.hashTree[0].hashTree.length > 0) {
let count = 0;
this.controller.hashTree[0].hashTree.forEach((item) => {
if (ELEMENTS.get("AllSamplerProxy").indexOf(item.type) !== -1) {
if (this.stepFilter.get("AllSamplerProxy").indexOf(item.type) !== -1) {
count++;
}
if (item.hashTree && item.hashTree.length > 0) {
@ -223,7 +224,7 @@ export default {
},
recursive(arr, count) {
for (let i in arr) {
if (ELEMENTS.get("AllSamplerProxy").indexOf(arr[i].type) !== -1) {
if (this.stepFilter.get("AllSamplerProxy").indexOf(arr[i].type) !== -1) {
count++;
}
if (arr[i].hashTree && arr[i].hashTree.length > 0) {

View File

@ -40,35 +40,53 @@
</span>
</template>
<!-- 这个不确定是否所以组件都有-->
<template v-slot:button v-if="allSampler.indexOf(request.type) !==-1">
<el-tooltip :content="$t('api_test.run')" placement="top" v-if="!loading">
<el-button :disabled="!request.enable" @click="run" icon="el-icon-video-play" style="padding: 5px" class="ms-btn" size="mini" circle/>
</el-tooltip>
<el-tooltip :content="$t('report.stop_btn')" placement="top" :enterable="false" v-else>
<el-button :disabled="!request.enable" @click.once="stop" size="mini" style="color:white;padding: 0 0.1px;width: 24px;height: 24px;" class="stop-btn" circle>
<div style="transform: scale(0.66)">
<span style="margin-left: -4.5px;font-weight: bold;">STOP</span>
</div>
</el-button>
</el-tooltip>
</template>
<template v-slot:result>
<p class="tip">{{ $t('api_test.definition.request.res_param') }} </p>
<div v-if="request.result">
<div v-for="(scenario,h) in request.result.scenarios" :key="h">
<el-tabs v-model="request.activeName" closable class="ms-tabs">
<el-tab-pane v-for="(item,i) in scenario.requestResults" :label="'循环'+(i+1)" :key="i" style="margin-bottom: 5px">
<api-response-component :currentProtocol="request.protocol" :apiActive="true" :result="item"/>
<div v-if="allSampler.indexOf(request.type) !==-1">
<p class="tip">{{ $t('api_test.definition.request.res_param') }} </p>
<div v-if="request.result">
<div v-for="(scenario,h) in request.result.scenarios" :key="h">
<el-tabs v-model="request.activeName" closable class="ms-tabs">
<el-tab-pane v-for="(item,i) in scenario.requestResults" :label="'循环'+(i+1)" :key="i" style="margin-bottom: 5px">
<api-response-component :currentProtocol="request.protocol" :apiActive="true" :result="item"/>
</el-tab-pane>
</el-tabs>
</div>
</div>
<div v-else>
<el-tabs v-model="request.activeName" closable class="ms-tabs" v-if="request.requestResult && request.requestResult.length > 1">
<el-tab-pane v-for="(item,i) in request.requestResult" :label="'循环'+(i+1)" :key="i" style="margin-bottom: 5px">
<api-response-component
:currentProtocol="request.protocol"
:apiActive="true"
:result="item"
/>
</el-tab-pane>
</el-tabs>
<api-response-component
:currentProtocol="request.protocol"
:apiActive="true"
:result="request.requestResult[0]"
v-else/>
</div>
</div>
<div v-else>
<el-tabs v-model="request.activeName" closable class="ms-tabs" v-if="request.requestResult && request.requestResult.length > 1">
<el-tab-pane v-for="(item,i) in request.requestResult" :label="'循环'+(i+1)" :key="i" style="margin-bottom: 5px">
<api-response-component
:currentProtocol="request.protocol"
:apiActive="true"
:result="item"
/>
</el-tab-pane>
</el-tabs>
<api-response-component
:currentProtocol="request.protocol"
:apiActive="true"
:result="request.requestResult[0]"
v-else/>
</div>
</template>
<ms-run :debug="true" :reportId="reportId" :run-data="runData" :env-map="envMap"
@runRefresh="runRefresh" @errorRefresh="errorRefresh" ref="runTest"/>
</api-base-component>
</template>
@ -77,12 +95,18 @@ import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent";
import formCreate from "@form-create/element-ui";
import MsUpload from "../common/MsPluginUpload";
import {PLUGIN_ELEMENTS} from "@/business/components/api/automation/scenario/Setting";
import {getUUID} from "@/common/js/utils";
formCreate.component("msUpload", MsUpload);
export default {
name: "PluginComponent",
components: {ApiBaseComponent, ApiResponseComponent},
components: {
ApiBaseComponent,
ApiResponseComponent,
MsRun: () => import("../../../definition/components/Run"),
},
props: {
draggable: {
type: Boolean,
@ -105,16 +129,21 @@ export default {
request: {
type: Object,
},
currentScenario: {},
defTitle: {type: String, default: "Plugin"},
defColor: {type: String, default: "#555855"},
defBackgroundColor: {type: String, default: "#F4F4FF"},
node: {},
envMap: Map,
},
data() {
return {
loading: false,
runData: [],
reportId: "",
pluginForm: {},
execEntry: "",
allSampler: PLUGIN_ELEMENTS.get("menu_generative_controller"),
data: {},
rules: [],
option: formCreate.parseJson(
@ -123,15 +152,39 @@ export default {
pluginName: "",
}
},
computed: {},
computed: {
isApiImport() {
if (this.request.referenced != undefined && this.request.referenced === 'Deleted' || this.request.referenced == 'REF' || this.request.referenced === 'Copy') {
return true
}
return false;
},
isExternalImport() {
if (this.request.referenced != undefined && this.request.referenced === 'OT_IMPORT') {
return true
}
return false;
},
isCustomizeReq() {
if (this.request.referenced == undefined || this.request.referenced === 'Created') {
return true;
}
return false;
},
isDeletedOrRef() {
if (this.request.referenced != undefined && this.request.referenced === 'Deleted' || this.request.referenced === 'REF') {
return true;
}
return false;
},
},
created() {
this.getPlugin();
if (!this.request.requestResult) {
this.request.requestResult = [];
}
this.data = this.request;
this.request.type = 'Sampler';
this.pluginName = this.request.type;
this.pluginName = this.request.stepName ? this.request.stepName : this.request.type;
},
watch: {
message() {
@ -149,6 +202,55 @@ export default {
},
change(d) {
},
run() {
if (this.isApiImport || this.request.isRefEnvironment) {
if (this.request.type && (this.request.type === "HTTPSamplerProxy" || this.request.type === "JDBCSampler" || this.request.type === "TCPSampler")) {
if (!this.envMap || this.envMap.size === 0) {
this.$warning(this.$t('api_test.automation.env_message'));
return false;
} else if (this.envMap && this.envMap.size > 0) {
const env = this.envMap.get(this.request.projectId);
if (!env) {
this.$warning(this.$t('api_test.automation.env_message'));
return false;
}
}
}
}
this.request.active = true;
this.loading = true;
this.runData = [];
this.runData.projectId = this.request.projectId;
this.request.useEnvironment = this.currentEnvironmentId;
this.request.customizeReq = this.isCustomizeReq;
let debugData = {
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
variables: this.currentScenario.variables, referenced: 'Created', headers: this.currentScenario.headers,
enableCookieShare: this.enableCookieShare, environmentId: this.currentEnvironmentId, hashTree: [this.request],
};
this.runData.push(debugData);
this.request.requestResult = [];
this.request.result = undefined;
/*触发执行操作*/
this.reportId = getUUID();
},
stop() {
let url = "/api/automation/stop/" + this.reportId;
this.$get(url, () => {
this.runLoading = false;
this.loading = false;
this.$success(this.$t('report.test_stop_success'));
});
},
errorRefresh() {
this.loading = false;
},
runRefresh(data) {
this.request.requestResult = [data];
this.request.result = undefined;
this.loading = false;
this.$emit('refReload', this.request, this.node);
},
getValue(val) {
let reg = /\{(\w+)\}/gi;
if (val.indexOf("${") !== -1) {
@ -180,18 +282,22 @@ export default {
if (id) {
this.$get('/plugin/get/' + id, response => {
let plugin = response.data;
this.pluginName = plugin.name;
this.execEntry = plugin.execEntry;
if (plugin && plugin.formScript) {
this.rules = formCreate.parseJson(plugin.formScript);
}
if (plugin && plugin.formOption) {
this.option = formCreate.parseJson(plugin.formOption);
}
this.option.submitBtn = {show: false};
this.request.clazzName = plugin.clazzName;
if (this.request && this.request.active && this.pluginForm) {
this.pluginForm.setValue(this.request);
if (plugin) {
this.pluginName = plugin.name;
this.execEntry = plugin.execEntry;
if (plugin.formScript) {
this.rules = formCreate.parseJson(plugin.formScript);
}
if (plugin.formOption) {
this.option = formCreate.parseJson(plugin.formOption);
}
this.option.submitBtn = {show: false};
this.request.clazzName = plugin.clazzName;
if (this.request && this.request.active && this.pluginForm) {
this.pluginForm.setValue(this.request);
}
} else {
this.request.enable = false;
}
});
}
@ -241,6 +347,11 @@ export default {
color: #67C23A;
}
.ms-btn {
background-color: #409EFF;
color: white;
}
.ms-step-debug-code {
display: inline-block;
margin: 0 5px;
@ -285,6 +396,12 @@ export default {
width: 100%;
}
.stop-btn {
background-color: #E62424;
border-color: #EE6161;
color: white;
}
.ms-form-create {
margin: 10px;
}

View File

@ -23,23 +23,27 @@
</template>
<script>
import {ELEMENTS} from "../Setting";
import {STEP} from "../Setting";
import MsVariableList from "../variable/VariableList";
import MsAddBasisApi from "../api/AddBasisApi";
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
export default {
name: "StepExtendBtns",
components: {ELEMENTS, MsVariableList, MsAddBasisApi},
components: {STEP, MsVariableList, MsAddBasisApi},
props: {
data: Object,
},
data() {
return {
allSamplers: ELEMENTS.get('AllSamplerProxy'),
allSamplers: [],
currentProtocol: "HTTP",
filter: new STEP,
}
},
mounted() {
this.allSamplers = this.filter.get('AllSamplerProxy')
},
methods: {
handleCommand(cmd) {
switch (cmd) {
@ -63,9 +67,9 @@ export default {
getScenario() {
this.result = this.$get("/api/automation/getApiScenario/" + this.data.id, response => {
if (response.data) {
if(response.data.projectId === getCurrentProjectID()) {
if (response.data.projectId === getCurrentProjectID()) {
this.$emit('openScenario', response.data);
}else{
} else {
let automationData = this.$router.resolve({
name: 'ApiAutomation',
params: {redirectID: getUUID(), dataType: "scenario", dataSelectRange: 'edit:' + response.data.id}

View File

@ -56,7 +56,7 @@
<vue-fab id="fab" mainBtnColor="#783887" size="small" :global-options="globalOptions"
:click-auto-close="false" ref="refFab">
<fab-item
v-for="(item, index) in buttons"
v-for="(item, index) in buttonData"
:key="index"
:idx="getIdx(index)"
:title="item.title"
@ -149,7 +149,7 @@
<script>
import {API_STATUS, PRIORITY} from "../../../definition/model/JsonData";
import {parseEnvironment} from "../../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS} from "../Setting";
import {ELEMENT_TYPE, STEP} from "../Setting";
import {getCurrentProjectID, getUUID, strMapToObj} from "@/common/js/utils";
import "@/common/css/material-icons.css"
import OutsideClick from "@/common/js/outside-click";
@ -243,15 +243,19 @@ export default {
expandedStatus: false,
stepEnable: true,
debugLoading: false,
buttonData: [],
stepFilter: new STEP,
}
},
created() {
if (!this.currentScenario.apiScenarioModuleId) {
this.currentScenario.apiScenarioModuleId = "";
}
this.operatingElements = ELEMENTS.get("ALL");
this.operatingElements = this.stepFilter.get("ALL");
this.projectEnvMap = this.envMap;
this.stepEnable = this.stepReEnable;
this.initPlugins();
this.buttonData = buttons(this);
},
mounted() {
this.$refs.refFab.openMenu();
@ -273,6 +277,29 @@ export default {
},
},
methods: {
initPlugins() {
let url = "/plugin/list";
this.$get(url, response => {
let data = response.data;
if (data) {
data.forEach(item => {
let plugin = {
title: item.name,
show: this.showButton(item.jmeterClazz),
titleColor: "#555855",
titleBgColor: "#F4F4FF",
icon: "colorize",
click: () => {
this.addComponent(item.name, item)
}
}
if (this.operatingElements && this.operatingElements.includes(item.jmeterClazz)) {
this.buttonData.push(plugin);
}
});
}
});
},
//
openScenario(data) {
this.$emit('openScenario', data);
@ -314,7 +341,7 @@ export default {
},
showNode(node) {
node.active = true;
if (node && ELEMENTS.get("AllSamplerProxy").indexOf(node.type) != -1) {
if (node && this.stepFilter.get("AllSamplerProxy").indexOf(node.type) != -1) {
return true;
}
return false;
@ -324,25 +351,18 @@ export default {
},
nodeClick(data, node) {
if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled) {
this.operatingElements = ELEMENTS.get(data.type);
this.operatingElements = this.stepFilter.get(data.type);
} else {
this.operatingElements = [];
}
if (data) {
data.active = true;
if (data.hashTree) {
data.hashTree.forEach(item => {
if (item) {
item.active = true;
}
})
}
} else {
data.active = false;
if (!this.operatingElements) {
this.operatingElements = this.stepFilter.get("ALL");
}
this.selectedTreeNode = data;
this.selectedNode = node;
this.$store.state.selectStep = data;
this.buttonData = buttons(this);
this.initPlugins();
},
suggestClick(node) {
this.response = {};
@ -354,7 +374,9 @@ export default {
},
showAll() {
if (!this.customizeVisible) {
this.operatingElements = ELEMENTS.get("ALL");
this.operatingElements = this.stepFilter.get("ALL");
this.buttonData = buttons(this);
this.initPlugins();
this.selectedTreeNode = undefined;
this.$store.state.selectStep = undefined;
}
@ -600,7 +622,7 @@ export default {
if (dropType != "inner") {
return true;
} else if (dropType === "inner" && dropNode.data.referenced !== 'REF' && dropNode.data.referenced !== 'Deleted'
&& ELEMENTS.get(dropNode.data.type).indexOf(draggingNode.data.type) != -1) {
&& this.stepFilter.get(dropNode.data.type).indexOf(draggingNode.data.type) != -1) {
return true;
}
return false;

View File

@ -200,7 +200,7 @@ export function setComponent(type, _this, plugin) {
_this.$refs.scenarioRelevance.open();
break;
default:
_this.scenarioDefinition.push(new PluginController({type: plugin.name, pluginId: plugin.scriptId}));
_this.scenarioDefinition.push(new PluginController({type: plugin.jmeterClazz,stepName:plugin.name, pluginId: plugin.scriptId}));
break;
}
if (_this.selectedNode) {

View File

@ -103,6 +103,7 @@ export default {
},
format(data) {
this.dataMap = new Map();
this.tableData = [];
data.forEach(item => {
if (this.dataMap.has(item.pluginId)) {
this.dataMap.get(item.pluginId).push(item);

View File

@ -151,7 +151,7 @@
import CaseComment from "@/business/components/track/case/components/CaseComment";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import MsPreviousNextButton from "../../../common/components/MsPreviousNextButton";
import {ELEMENTS} from "@/business/components/api/automation/scenario/Setting";
import {STEP} from "@/business/components/api/automation/scenario/Setting";
import TestCaseComment from "@/business/components/track/case/components/TestCaseComment";
import ReviewCommentItem from "@/business/components/track/review/commom/ReviewCommentItem";
import {API_STATUS, REVIEW_STATUS, TEST, TEST_CASE} from "@/business/components/api/definition/model/JsonData";
@ -267,6 +267,7 @@
index: 0,
showInputTag: true,
tableType: "",
stepFilter: new STEP,
moduleObj: {
id: 'id',
label: 'name',
@ -440,7 +441,7 @@
},
showAll() {
if (!this.customizeVisible) {
this.operatingElements = ELEMENTS.get("ALL");
this.operatingElements = this.stepFilter.get("ALL");
this.selectedTreeNode = undefined;
}
//this.reload();