diff --git a/backend/pom.xml b/backend/pom.xml index ea153a84bc..dc9d501331 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -150,6 +150,10 @@ org.apache.logging.log4j log4j-slf4j-impl + + org.apache-extras.beanshell + bsh + @@ -516,6 +520,15 @@ src/main/resources/jmeter/lib/ext jython-standalone.jar + + org.apache-extras.beanshell + bsh + 2.0b6 + jar + true + src/main/resources/jmeter/lib/ext + bsh-2.0b6.jar + ${project.build.directory}/wars false @@ -594,4 +607,4 @@ - + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java b/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java index 8a381e7d36..f6bd0a53b8 100644 --- a/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java +++ b/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java @@ -6,6 +6,7 @@ import io.metersphere.commons.utils.LogUtil; import io.metersphere.config.JmeterProperties; import io.metersphere.i18n.Translator; import org.apache.commons.lang3.StringUtils; +import org.apache.jmeter.NewDriver; import org.apache.jmeter.config.Arguments; import org.apache.jmeter.save.SaveService; import org.apache.jmeter.util.JMeterUtils; @@ -29,6 +30,8 @@ public class JMeterService { public void run(String testId, String debugReportId, InputStream is) { String JMETER_HOME = getJmeterHome(); + NewDriver.setContextClassLoader(); + String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties"; JMeterUtils.loadJMeterProperties(JMETER_PROPERTIES); JMeterUtils.setJMeterHome(JMETER_HOME); diff --git a/backend/src/main/java/io/metersphere/api/jmeter/NewDriverManager.java b/backend/src/main/java/io/metersphere/api/jmeter/NewDriverManager.java new file mode 100644 index 0000000000..6d77c476c8 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/jmeter/NewDriverManager.java @@ -0,0 +1,31 @@ +package io.metersphere.api.jmeter; + +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; +import org.apache.jmeter.NewDriver; + +import java.io.File; +import java.net.MalformedURLException; + +public class NewDriverManager { + + public static void loadJar(File file) { + if (file != null) { + try { + NewDriver.addURL(file.toURI().toURL()); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + MSException.throwException(e.getMessage()); + } + } + } + + public static void loadJar(String path) { + try { + NewDriver.addPath(path); + } catch (MalformedURLException e) { + LogUtil.error(e.getMessage(), e); + MSException.throwException(e.getMessage()); + } + } +} diff --git a/backend/src/main/java/io/metersphere/base/domain/JarConfig.java b/backend/src/main/java/io/metersphere/base/domain/JarConfig.java new file mode 100644 index 0000000000..902602d063 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/JarConfig.java @@ -0,0 +1,29 @@ +package io.metersphere.base.domain; + +import java.io.Serializable; +import lombok.Data; + +@Data +public class JarConfig implements Serializable { + private String id; + + private String name; + + private String fileName; + + private String creator; + + private String modifier; + + private String path; + + private Boolean enable; + + private String description; + + private Long createTime; + + private Long updateTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/JarConfigExample.java b/backend/src/main/java/io/metersphere/base/domain/JarConfigExample.java new file mode 100644 index 0000000000..fc6feb2fcc --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/JarConfigExample.java @@ -0,0 +1,870 @@ +package io.metersphere.base.domain; + +import java.util.ArrayList; +import java.util.List; + +public class JarConfigExample { + protected String orderByClause; + + protected boolean distinct; + + protected List oredCriteria; + + public JarConfigExample() { + oredCriteria = new ArrayList(); + } + + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; + } + + public String getOrderByClause() { + return orderByClause; + } + + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + + public boolean isDistinct() { + return distinct; + } + + public List getOredCriteria() { + return oredCriteria; + } + + public void or(Criteria criteria) { + oredCriteria.add(criteria); + } + + public Criteria or() { + Criteria criteria = createCriteriaInternal(); + oredCriteria.add(criteria); + return criteria; + } + + public Criteria createCriteria() { + Criteria criteria = createCriteriaInternal(); + if (oredCriteria.size() == 0) { + oredCriteria.add(criteria); + } + return criteria; + } + + protected Criteria createCriteriaInternal() { + Criteria criteria = new Criteria(); + return criteria; + } + + public void clear() { + oredCriteria.clear(); + orderByClause = null; + distinct = false; + } + + protected abstract static class GeneratedCriteria { + protected List criteria; + + protected GeneratedCriteria() { + super(); + criteria = new ArrayList(); + } + + public boolean isValid() { + return criteria.size() > 0; + } + + public List getAllCriteria() { + return criteria; + } + + public List getCriteria() { + return criteria; + } + + protected void addCriterion(String condition) { + if (condition == null) { + throw new RuntimeException("Value for condition cannot be null"); + } + criteria.add(new Criterion(condition)); + } + + protected void addCriterion(String condition, Object value, String property) { + if (value == null) { + throw new RuntimeException("Value for " + property + " cannot be null"); + } + criteria.add(new Criterion(condition, value)); + } + + protected void addCriterion(String condition, Object value1, Object value2, String property) { + if (value1 == null || value2 == null) { + throw new RuntimeException("Between values for " + property + " cannot be null"); + } + criteria.add(new Criterion(condition, value1, value2)); + } + + public Criteria andIdIsNull() { + addCriterion("id is null"); + return (Criteria) this; + } + + public Criteria andIdIsNotNull() { + addCriterion("id is not null"); + return (Criteria) this; + } + + public Criteria andIdEqualTo(String value) { + addCriterion("id =", value, "id"); + return (Criteria) this; + } + + public Criteria andIdNotEqualTo(String value) { + addCriterion("id <>", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThan(String value) { + addCriterion("id >", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThanOrEqualTo(String value) { + addCriterion("id >=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThan(String value) { + addCriterion("id <", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThanOrEqualTo(String value) { + addCriterion("id <=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLike(String value) { + addCriterion("id like", value, "id"); + return (Criteria) this; + } + + public Criteria andIdNotLike(String value) { + addCriterion("id not like", value, "id"); + return (Criteria) this; + } + + public Criteria andIdIn(List values) { + addCriterion("id in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdNotIn(List values) { + addCriterion("id not in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdBetween(String value1, String value2) { + addCriterion("id between", value1, value2, "id"); + return (Criteria) this; + } + + public Criteria andIdNotBetween(String value1, String value2) { + addCriterion("id not between", value1, value2, "id"); + return (Criteria) this; + } + + public Criteria andNameIsNull() { + addCriterion("`name` is null"); + return (Criteria) this; + } + + public Criteria andNameIsNotNull() { + addCriterion("`name` is not null"); + return (Criteria) this; + } + + public Criteria andNameEqualTo(String value) { + addCriterion("`name` =", value, "name"); + return (Criteria) this; + } + + public Criteria andNameNotEqualTo(String value) { + addCriterion("`name` <>", value, "name"); + return (Criteria) this; + } + + public Criteria andNameGreaterThan(String value) { + addCriterion("`name` >", value, "name"); + return (Criteria) this; + } + + public Criteria andNameGreaterThanOrEqualTo(String value) { + addCriterion("`name` >=", value, "name"); + return (Criteria) this; + } + + public Criteria andNameLessThan(String value) { + addCriterion("`name` <", value, "name"); + return (Criteria) this; + } + + public Criteria andNameLessThanOrEqualTo(String value) { + addCriterion("`name` <=", value, "name"); + return (Criteria) this; + } + + public Criteria andNameLike(String value) { + addCriterion("`name` like", value, "name"); + return (Criteria) this; + } + + public Criteria andNameNotLike(String value) { + addCriterion("`name` not like", value, "name"); + return (Criteria) this; + } + + public Criteria andNameIn(List values) { + addCriterion("`name` in", values, "name"); + return (Criteria) this; + } + + public Criteria andNameNotIn(List values) { + addCriterion("`name` not in", values, "name"); + return (Criteria) this; + } + + public Criteria andNameBetween(String value1, String value2) { + addCriterion("`name` between", value1, value2, "name"); + return (Criteria) this; + } + + public Criteria andNameNotBetween(String value1, String value2) { + addCriterion("`name` not between", value1, value2, "name"); + return (Criteria) this; + } + + public Criteria andFileNameIsNull() { + addCriterion("file_name is null"); + return (Criteria) this; + } + + public Criteria andFileNameIsNotNull() { + addCriterion("file_name is not null"); + return (Criteria) this; + } + + public Criteria andFileNameEqualTo(String value) { + addCriterion("file_name =", value, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameNotEqualTo(String value) { + addCriterion("file_name <>", value, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameGreaterThan(String value) { + addCriterion("file_name >", value, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameGreaterThanOrEqualTo(String value) { + addCriterion("file_name >=", value, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameLessThan(String value) { + addCriterion("file_name <", value, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameLessThanOrEqualTo(String value) { + addCriterion("file_name <=", value, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameLike(String value) { + addCriterion("file_name like", value, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameNotLike(String value) { + addCriterion("file_name not like", value, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameIn(List values) { + addCriterion("file_name in", values, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameNotIn(List values) { + addCriterion("file_name not in", values, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameBetween(String value1, String value2) { + addCriterion("file_name between", value1, value2, "fileName"); + return (Criteria) this; + } + + public Criteria andFileNameNotBetween(String value1, String value2) { + addCriterion("file_name not between", value1, value2, "fileName"); + return (Criteria) this; + } + + public Criteria andCreatorIsNull() { + addCriterion("creator is null"); + return (Criteria) this; + } + + public Criteria andCreatorIsNotNull() { + addCriterion("creator is not null"); + return (Criteria) this; + } + + public Criteria andCreatorEqualTo(String value) { + addCriterion("creator =", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorNotEqualTo(String value) { + addCriterion("creator <>", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorGreaterThan(String value) { + addCriterion("creator >", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorGreaterThanOrEqualTo(String value) { + addCriterion("creator >=", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorLessThan(String value) { + addCriterion("creator <", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorLessThanOrEqualTo(String value) { + addCriterion("creator <=", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorLike(String value) { + addCriterion("creator like", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorNotLike(String value) { + addCriterion("creator not like", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorIn(List values) { + addCriterion("creator in", values, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorNotIn(List values) { + addCriterion("creator not in", values, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorBetween(String value1, String value2) { + addCriterion("creator between", value1, value2, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorNotBetween(String value1, String value2) { + addCriterion("creator not between", value1, value2, "creator"); + return (Criteria) this; + } + + public Criteria andModifierIsNull() { + addCriterion("modifier is null"); + return (Criteria) this; + } + + public Criteria andModifierIsNotNull() { + addCriterion("modifier is not null"); + return (Criteria) this; + } + + public Criteria andModifierEqualTo(String value) { + addCriterion("modifier =", value, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierNotEqualTo(String value) { + addCriterion("modifier <>", value, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierGreaterThan(String value) { + addCriterion("modifier >", value, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierGreaterThanOrEqualTo(String value) { + addCriterion("modifier >=", value, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierLessThan(String value) { + addCriterion("modifier <", value, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierLessThanOrEqualTo(String value) { + addCriterion("modifier <=", value, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierLike(String value) { + addCriterion("modifier like", value, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierNotLike(String value) { + addCriterion("modifier not like", value, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierIn(List values) { + addCriterion("modifier in", values, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierNotIn(List values) { + addCriterion("modifier not in", values, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierBetween(String value1, String value2) { + addCriterion("modifier between", value1, value2, "modifier"); + return (Criteria) this; + } + + public Criteria andModifierNotBetween(String value1, String value2) { + addCriterion("modifier not between", value1, value2, "modifier"); + return (Criteria) this; + } + + public Criteria andPathIsNull() { + addCriterion("`path` is null"); + return (Criteria) this; + } + + public Criteria andPathIsNotNull() { + addCriterion("`path` is not null"); + return (Criteria) this; + } + + public Criteria andPathEqualTo(String value) { + addCriterion("`path` =", value, "path"); + return (Criteria) this; + } + + public Criteria andPathNotEqualTo(String value) { + addCriterion("`path` <>", value, "path"); + return (Criteria) this; + } + + public Criteria andPathGreaterThan(String value) { + addCriterion("`path` >", value, "path"); + return (Criteria) this; + } + + public Criteria andPathGreaterThanOrEqualTo(String value) { + addCriterion("`path` >=", value, "path"); + return (Criteria) this; + } + + public Criteria andPathLessThan(String value) { + addCriterion("`path` <", value, "path"); + return (Criteria) this; + } + + public Criteria andPathLessThanOrEqualTo(String value) { + addCriterion("`path` <=", value, "path"); + return (Criteria) this; + } + + public Criteria andPathLike(String value) { + addCriterion("`path` like", value, "path"); + return (Criteria) this; + } + + public Criteria andPathNotLike(String value) { + addCriterion("`path` not like", value, "path"); + return (Criteria) this; + } + + public Criteria andPathIn(List values) { + addCriterion("`path` in", values, "path"); + return (Criteria) this; + } + + public Criteria andPathNotIn(List values) { + addCriterion("`path` not in", values, "path"); + return (Criteria) this; + } + + public Criteria andPathBetween(String value1, String value2) { + addCriterion("`path` between", value1, value2, "path"); + return (Criteria) this; + } + + public Criteria andPathNotBetween(String value1, String value2) { + addCriterion("`path` not between", value1, value2, "path"); + return (Criteria) this; + } + + public Criteria andEnableIsNull() { + addCriterion("`enable` is null"); + return (Criteria) this; + } + + public Criteria andEnableIsNotNull() { + addCriterion("`enable` is not null"); + return (Criteria) this; + } + + public Criteria andEnableEqualTo(Boolean value) { + addCriterion("`enable` =", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableNotEqualTo(Boolean value) { + addCriterion("`enable` <>", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableGreaterThan(Boolean value) { + addCriterion("`enable` >", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableGreaterThanOrEqualTo(Boolean value) { + addCriterion("`enable` >=", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableLessThan(Boolean value) { + addCriterion("`enable` <", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableLessThanOrEqualTo(Boolean value) { + addCriterion("`enable` <=", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableIn(List values) { + addCriterion("`enable` in", values, "enable"); + return (Criteria) this; + } + + public Criteria andEnableNotIn(List values) { + addCriterion("`enable` not in", values, "enable"); + return (Criteria) this; + } + + public Criteria andEnableBetween(Boolean value1, Boolean value2) { + addCriterion("`enable` between", value1, value2, "enable"); + return (Criteria) this; + } + + public Criteria andEnableNotBetween(Boolean value1, Boolean value2) { + addCriterion("`enable` not between", value1, value2, "enable"); + return (Criteria) this; + } + + public Criteria andDescriptionIsNull() { + addCriterion("description is null"); + return (Criteria) this; + } + + public Criteria andDescriptionIsNotNull() { + addCriterion("description is not null"); + return (Criteria) this; + } + + public Criteria andDescriptionEqualTo(String value) { + addCriterion("description =", value, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionNotEqualTo(String value) { + addCriterion("description <>", value, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionGreaterThan(String value) { + addCriterion("description >", value, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionGreaterThanOrEqualTo(String value) { + addCriterion("description >=", value, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionLessThan(String value) { + addCriterion("description <", value, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionLessThanOrEqualTo(String value) { + addCriterion("description <=", value, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionLike(String value) { + addCriterion("description like", value, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionNotLike(String value) { + addCriterion("description not like", value, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionIn(List values) { + addCriterion("description in", values, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionNotIn(List values) { + addCriterion("description not in", values, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionBetween(String value1, String value2) { + addCriterion("description between", value1, value2, "description"); + return (Criteria) this; + } + + public Criteria andDescriptionNotBetween(String value1, String value2) { + addCriterion("description not between", value1, value2, "description"); + return (Criteria) this; + } + + public Criteria andCreateTimeIsNull() { + addCriterion("create_time is null"); + return (Criteria) this; + } + + public Criteria andCreateTimeIsNotNull() { + addCriterion("create_time is not null"); + return (Criteria) this; + } + + public Criteria andCreateTimeEqualTo(Long value) { + addCriterion("create_time =", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotEqualTo(Long value) { + addCriterion("create_time <>", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeGreaterThan(Long value) { + addCriterion("create_time >", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) { + addCriterion("create_time >=", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeLessThan(Long value) { + addCriterion("create_time <", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeLessThanOrEqualTo(Long value) { + addCriterion("create_time <=", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeIn(List values) { + addCriterion("create_time in", values, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotIn(List values) { + addCriterion("create_time not in", values, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeBetween(Long value1, Long value2) { + addCriterion("create_time between", value1, value2, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotBetween(Long value1, Long value2) { + addCriterion("create_time not between", value1, value2, "createTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeIsNull() { + addCriterion("update_time is null"); + return (Criteria) this; + } + + public Criteria andUpdateTimeIsNotNull() { + addCriterion("update_time is not null"); + return (Criteria) this; + } + + public Criteria andUpdateTimeEqualTo(Long value) { + addCriterion("update_time =", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeNotEqualTo(Long value) { + addCriterion("update_time <>", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeGreaterThan(Long value) { + addCriterion("update_time >", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) { + addCriterion("update_time >=", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeLessThan(Long value) { + addCriterion("update_time <", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeLessThanOrEqualTo(Long value) { + addCriterion("update_time <=", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeIn(List values) { + addCriterion("update_time in", values, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeNotIn(List values) { + addCriterion("update_time not in", values, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeBetween(Long value1, Long value2) { + addCriterion("update_time between", value1, value2, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeNotBetween(Long value1, Long value2) { + addCriterion("update_time not between", value1, value2, "updateTime"); + return (Criteria) this; + } + } + + public static class Criteria extends GeneratedCriteria { + + protected Criteria() { + super(); + } + } + + public static class Criterion { + private String condition; + + private Object value; + + private Object secondValue; + + private boolean noValue; + + private boolean singleValue; + + private boolean betweenValue; + + private boolean listValue; + + private String typeHandler; + + public String getCondition() { + return condition; + } + + public Object getValue() { + return value; + } + + public Object getSecondValue() { + return secondValue; + } + + public boolean isNoValue() { + return noValue; + } + + public boolean isSingleValue() { + return singleValue; + } + + public boolean isBetweenValue() { + return betweenValue; + } + + public boolean isListValue() { + return listValue; + } + + public String getTypeHandler() { + return typeHandler; + } + + protected Criterion(String condition) { + super(); + this.condition = condition; + this.typeHandler = null; + this.noValue = true; + } + + protected Criterion(String condition, Object value, String typeHandler) { + super(); + this.condition = condition; + this.value = value; + this.typeHandler = typeHandler; + if (value instanceof List) { + this.listValue = true; + } else { + this.singleValue = true; + } + } + + protected Criterion(String condition, Object value) { + this(condition, value, null); + } + + protected Criterion(String condition, Object value, Object secondValue, String typeHandler) { + super(); + this.condition = condition; + this.value = value; + this.secondValue = secondValue; + this.typeHandler = typeHandler; + this.betweenValue = true; + } + + protected Criterion(String condition, Object value, Object secondValue) { + this(condition, value, secondValue, null); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/JarConfigMapper.java b/backend/src/main/java/io/metersphere/base/mapper/JarConfigMapper.java new file mode 100644 index 0000000000..eebeb076b3 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/JarConfigMapper.java @@ -0,0 +1,30 @@ +package io.metersphere.base.mapper; + +import io.metersphere.base.domain.JarConfig; +import io.metersphere.base.domain.JarConfigExample; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +public interface JarConfigMapper { + long countByExample(JarConfigExample example); + + int deleteByExample(JarConfigExample example); + + int deleteByPrimaryKey(String id); + + int insert(JarConfig record); + + int insertSelective(JarConfig record); + + List selectByExample(JarConfigExample example); + + JarConfig selectByPrimaryKey(String id); + + int updateByExampleSelective(@Param("record") JarConfig record, @Param("example") JarConfigExample example); + + int updateByExample(@Param("record") JarConfig record, @Param("example") JarConfigExample example); + + int updateByPrimaryKeySelective(JarConfig record); + + int updateByPrimaryKey(JarConfig record); +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/JarConfigMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/JarConfigMapper.xml new file mode 100644 index 0000000000..351b640120 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/JarConfigMapper.xml @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + id, `name`, file_name, creator, modifier, `path`, `enable`, description, create_time, + update_time + + + + + delete from jar_config + where id = #{id,jdbcType=VARCHAR} + + + delete from jar_config + + + + + + insert into jar_config (id, `name`, file_name, + creator, modifier, `path`, + `enable`, description, create_time, + update_time) + values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{fileName,jdbcType=VARCHAR}, + #{creator,jdbcType=VARCHAR}, #{modifier,jdbcType=VARCHAR}, #{path,jdbcType=VARCHAR}, + #{enable,jdbcType=BIT}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, + #{updateTime,jdbcType=BIGINT}) + + + insert into jar_config + + + id, + + + `name`, + + + file_name, + + + creator, + + + modifier, + + + `path`, + + + `enable`, + + + description, + + + create_time, + + + update_time, + + + + + #{id,jdbcType=VARCHAR}, + + + #{name,jdbcType=VARCHAR}, + + + #{fileName,jdbcType=VARCHAR}, + + + #{creator,jdbcType=VARCHAR}, + + + #{modifier,jdbcType=VARCHAR}, + + + #{path,jdbcType=VARCHAR}, + + + #{enable,jdbcType=BIT}, + + + #{description,jdbcType=VARCHAR}, + + + #{createTime,jdbcType=BIGINT}, + + + #{updateTime,jdbcType=BIGINT}, + + + + + + update jar_config + + + id = #{record.id,jdbcType=VARCHAR}, + + + `name` = #{record.name,jdbcType=VARCHAR}, + + + file_name = #{record.fileName,jdbcType=VARCHAR}, + + + creator = #{record.creator,jdbcType=VARCHAR}, + + + modifier = #{record.modifier,jdbcType=VARCHAR}, + + + `path` = #{record.path,jdbcType=VARCHAR}, + + + `enable` = #{record.enable,jdbcType=BIT}, + + + description = #{record.description,jdbcType=VARCHAR}, + + + create_time = #{record.createTime,jdbcType=BIGINT}, + + + update_time = #{record.updateTime,jdbcType=BIGINT}, + + + + + + + + update jar_config + set id = #{record.id,jdbcType=VARCHAR}, + `name` = #{record.name,jdbcType=VARCHAR}, + file_name = #{record.fileName,jdbcType=VARCHAR}, + creator = #{record.creator,jdbcType=VARCHAR}, + modifier = #{record.modifier,jdbcType=VARCHAR}, + `path` = #{record.path,jdbcType=VARCHAR}, + `enable` = #{record.enable,jdbcType=BIT}, + description = #{record.description,jdbcType=VARCHAR}, + create_time = #{record.createTime,jdbcType=BIGINT}, + update_time = #{record.updateTime,jdbcType=BIGINT} + + + + + + update jar_config + + + `name` = #{name,jdbcType=VARCHAR}, + + + file_name = #{fileName,jdbcType=VARCHAR}, + + + creator = #{creator,jdbcType=VARCHAR}, + + + modifier = #{modifier,jdbcType=VARCHAR}, + + + `path` = #{path,jdbcType=VARCHAR}, + + + `enable` = #{enable,jdbcType=BIT}, + + + description = #{description,jdbcType=VARCHAR}, + + + create_time = #{createTime,jdbcType=BIGINT}, + + + update_time = #{updateTime,jdbcType=BIGINT}, + + + where id = #{id,jdbcType=VARCHAR} + + + update jar_config + set `name` = #{name,jdbcType=VARCHAR}, + file_name = #{fileName,jdbcType=VARCHAR}, + creator = #{creator,jdbcType=VARCHAR}, + modifier = #{modifier,jdbcType=VARCHAR}, + `path` = #{path,jdbcType=VARCHAR}, + `enable` = #{enable,jdbcType=BIT}, + description = #{description,jdbcType=VARCHAR}, + create_time = #{createTime,jdbcType=BIGINT}, + update_time = #{updateTime,jdbcType=BIGINT} + where id = #{id,jdbcType=VARCHAR} + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java b/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java index 427d75630a..f2d33539d7 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java +++ b/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java @@ -9,5 +9,9 @@ public interface NoticeConstants { String CREATE = "CREATE"; String UPDATE = "CREATE"; String DELETE = "DELETE"; + String JENKINS_TASK = "jenkinsTask"; + String TEST_PLAN_TASK = "testPlanTask"; + String REVIEW_TASK = "reviewTask"; + String DEFECT_TASK = "defectTask"; } diff --git a/backend/src/main/java/io/metersphere/controller/JarConfigController.java b/backend/src/main/java/io/metersphere/controller/JarConfigController.java new file mode 100644 index 0000000000..a2e2aa1567 --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/JarConfigController.java @@ -0,0 +1,61 @@ +package io.metersphere.controller; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import io.metersphere.base.domain.JarConfig; +import io.metersphere.commons.constants.RoleConstants; +import io.metersphere.commons.utils.PageUtils; +import io.metersphere.commons.utils.Pager; +import io.metersphere.service.JarConfigService; +import org.apache.shiro.authz.annotation.Logical; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.util.List; + +@RestController +@RequestMapping(value = "/jar") +@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR) +public class JarConfigController { + + @Resource + JarConfigService JarConfigService; + + @PostMapping("list/{goPage}/{pageSize}") + @RequiresRoles(RoleConstants.ORG_ADMIN) + public Pager> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody JarConfig request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + return PageUtils.setPageInfo(page, JarConfigService.list(request)); + } + + @GetMapping("list/all") + public List listAll() { + return JarConfigService.list(); + } + + @GetMapping("/get/{id}") + public JarConfig get(@PathVariable String id) { + return JarConfigService.get(id); + } + + @PostMapping(value = "/add", consumes = {"multipart/form-data"}) + @RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER,}, logical = Logical.OR) + public String add(@RequestPart("request") JarConfig request, @RequestPart(value = "file") MultipartFile file) { + return JarConfigService.add(request, file); + } + + @PostMapping(value = "/update", consumes = {"multipart/form-data"}) + @RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER,}, logical = Logical.OR) + public void update(@RequestPart("request") JarConfig request, @RequestPart(value = "file", required = false) MultipartFile file) { + JarConfigService.update(request, file); + } + + @GetMapping("/delete/{id}") + @RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER,}, logical = Logical.OR) + public void delete(@PathVariable String id) { + JarConfigService.delete(id); + } + +} diff --git a/backend/src/main/java/io/metersphere/listener/AppStartListener.java b/backend/src/main/java/io/metersphere/listener/AppStartListener.java index 6f25d0fd66..0b55a6cd91 100644 --- a/backend/src/main/java/io/metersphere/listener/AppStartListener.java +++ b/backend/src/main/java/io/metersphere/listener/AppStartListener.java @@ -1,15 +1,20 @@ package io.metersphere.listener; import io.metersphere.api.jmeter.JMeterService; +import io.metersphere.api.jmeter.NewDriverManager; +import io.metersphere.base.domain.JarConfig; import io.metersphere.commons.utils.LogUtil; +import io.metersphere.service.JarConfigService; import io.metersphere.service.ScheduleService; import org.python.core.Options; import org.python.util.PythonInterpreter; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.util.List; @Component public class AppStartListener implements ApplicationListener { @@ -18,12 +23,20 @@ public class AppStartListener implements ApplicationListener jars = jarConfigService.list(); + try { + jars.forEach(jarConfig -> { + NewDriverManager.loadJar(jarConfig.getPath()); + }); + } catch (Exception e) { + e.printStackTrace(); + LogUtil.error(e.getMessage(), e); + } + } } diff --git a/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java b/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java index fdfe68436c..7696b2ba0f 100644 --- a/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java +++ b/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java @@ -32,7 +32,7 @@ public class NoticeController { } @GetMapping("/search/message") - public List searchMessage() { + public MessageSettingDetail searchMessage() { return noticeService.searchMessage(); } diff --git a/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java b/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java index 45f40beabf..2550cbc864 100644 --- a/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java +++ b/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java @@ -9,7 +9,6 @@ import java.util.List; @Data public class MessageDetail extends MessageTask { private List userIds = new ArrayList<>(); - private List userNames = new ArrayList<>(); private List events = new ArrayList<>(); private String taskType; private String webhook; diff --git a/backend/src/main/java/io/metersphere/notice/service/NoticeService.java b/backend/src/main/java/io/metersphere/notice/service/NoticeService.java index 658001a1db..7fbe8e01e1 100644 --- a/backend/src/main/java/io/metersphere/notice/service/NoticeService.java +++ b/backend/src/main/java/io/metersphere/notice/service/NoticeService.java @@ -6,17 +6,18 @@ import io.metersphere.base.domain.Notice; import io.metersphere.base.domain.NoticeExample; import io.metersphere.base.mapper.MessageTaskMapper; import io.metersphere.base.mapper.NoticeMapper; +import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.notice.controller.request.MessageRequest; import io.metersphere.notice.controller.request.NoticeRequest; +import io.metersphere.notice.domain.MessageDetail; import io.metersphere.notice.domain.MessageSettingDetail; import io.metersphere.notice.domain.NoticeDetail; import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; import static io.metersphere.commons.constants.NoticeConstants.EXECUTE_FAILED; import static io.metersphere.commons.constants.NoticeConstants.EXECUTE_SUCCESSFUL; @@ -86,7 +87,7 @@ public class NoticeService { } public void saveMessageTask(MessageRequest messageRequest) { - String identification=UUID.randomUUID().toString(); + String identification = UUID.randomUUID().toString(); messageRequest.getMessageDetail().forEach(list -> { list.getEvents().forEach(n -> { list.getUserIds().forEach(m -> { @@ -106,12 +107,42 @@ public class NoticeService { } - public List searchMessage() { + public MessageSettingDetail searchMessage() { MessageTaskExample messageTaskExample = new MessageTaskExample(); messageTaskExample.createCriteria(); - List messageTasks = new ArrayList<>(); - List messageSettingDetail = new ArrayList<>(); - messageTasks = messageTaskMapper.selectByExample(messageTaskExample); + List messageTaskLists = new ArrayList<>(); + MessageSettingDetail messageSettingDetail = new MessageSettingDetail(); + List MessageDetailList = new ArrayList<>(); + messageTaskLists = messageTaskMapper.selectByExample(messageTaskExample); + Map> MessageTaskMap = messageTaskLists.stream().collect(Collectors.groupingBy(e -> fetchGroupKey(e))); + MessageTaskMap.forEach((k, v) -> { + Set userIds = new HashSet(); + Set events = new HashSet(); + MessageDetail messageDetail = new MessageDetail(); + for (MessageTask m : v) { + userIds.add(m.getUserId()); + events.add(m.getEvent()); + messageDetail.setTaskType(m.getTaskType()); + messageDetail.setWebhook(m.getWebhook()); + messageDetail.setIdentification(m.getIdentification()); + messageDetail.setType(m.getType()); + } + messageDetail.setEvents(new ArrayList(events)); + messageDetail.setUserIds(new ArrayList(userIds)); + MessageDetailList.add(messageDetail); + }); + List jenkinsTask = MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.JENKINS_TASK)).collect(Collectors.toList()); + List testCasePlanTask = MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.TEST_PLAN_TASK)).collect(Collectors.toList()); + List reviewTask = MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.REVIEW_TASK)).collect(Collectors.toList()); + List defectTask = MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.DEFECT_TASK)).collect(Collectors.toList()); + messageSettingDetail.setJenkinsTask(jenkinsTask); + messageSettingDetail.setTestCasePlanTask(testCasePlanTask); + messageSettingDetail.setReviewTask(reviewTask); + messageSettingDetail.setDefectTask(defectTask); return messageSettingDetail; } + + private static String fetchGroupKey(MessageTask user) { + return user.getTaskType() + "#" + user.getIdentification(); + } } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/service/JarConfigService.java b/backend/src/main/java/io/metersphere/service/JarConfigService.java new file mode 100644 index 0000000000..f278fbd069 --- /dev/null +++ b/backend/src/main/java/io/metersphere/service/JarConfigService.java @@ -0,0 +1,141 @@ +package io.metersphere.service; + +import io.metersphere.api.jmeter.NewDriverManager; +import io.metersphere.base.domain.JarConfig; +import io.metersphere.base.domain.JarConfigExample; +import io.metersphere.base.mapper.JarConfigMapper; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; +import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.i18n.Translator; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.util.FileUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.*; +import java.util.List; +import java.util.UUID; + +@Service +@Transactional(rollbackFor = Exception.class) +public class JarConfigService { + + private static final String JAR_FILE_DIR = "/opt/metersphere/data/jar"; + + @Resource + private JarConfigMapper jarConfigMapper; + + public List list() { + JarConfigExample example = new JarConfigExample(); + return jarConfigMapper.selectByExample(example); + } + + public List list(JarConfig jarConfig) { + JarConfigExample example = new JarConfigExample(); + if (StringUtils.isNotBlank(jarConfig.getName())) { + example.createCriteria().andNameLike("%" + jarConfig.getName() + "%"); + } + example.setOrderByClause("update_time desc"); + return jarConfigMapper.selectByExample(example); + } + + public JarConfig get(String id) { + return jarConfigMapper.selectByPrimaryKey(id); + } + + public void delete(String id) { + JarConfig JarConfig = jarConfigMapper.selectByPrimaryKey(id); + deleteJarFile(JarConfig.getPath()); + jarConfigMapper.deleteByPrimaryKey(id); + } + + public void update(JarConfig jarConfig, MultipartFile file) { + checkExist(jarConfig); + jarConfig.setEnable(true);// todo 审批机制时需修改 + jarConfig.setModifier(SessionUtils.getUser().getId()); + jarConfig.setUpdateTime(System.currentTimeMillis()); + String deletePath = jarConfig.getPath(); + if (file != null) { + jarConfig.setFileName(file.getOriginalFilename()); + jarConfig.setPath(getJarPath(file)); + } + jarConfigMapper.updateByPrimaryKey(jarConfig); + if (file != null) { + deleteJarFile(deletePath); + createJarFiles(file); + NewDriverManager.loadJar(jarConfig.getPath()); + } + } + + public String add(JarConfig jarConfig, MultipartFile file) { + jarConfig.setId(UUID.randomUUID().toString()); + jarConfig.setCreator(SessionUtils.getUser().getId()); + jarConfig.setModifier(SessionUtils.getUser().getId()); + checkExist(jarConfig); + jarConfig.setEnable(true);// todo 审批机制时需修改 + jarConfig.setCreateTime(System.currentTimeMillis()); + jarConfig.setUpdateTime(System.currentTimeMillis()); + jarConfig.setPath(getJarPath(file)); + jarConfig.setFileName(file.getOriginalFilename()); + jarConfigMapper.insert(jarConfig); + createJarFiles(file); + NewDriverManager.loadJar(jarConfig.getPath()); + return jarConfig.getId(); + } + + public void deleteJarFiles(String testId) { + File file = new File(JAR_FILE_DIR + "/" + testId); + FileUtil.deleteContents(file); + if (file.exists()) { + file.delete(); + } + } + + public void deleteJarFile(String path) { + File file = new File(path); + if (file.exists()) { + file.delete(); + } + } + + public String getJarPath(MultipartFile file) { + return JAR_FILE_DIR + "/" + file.getOriginalFilename(); + } + + private String createJarFiles(MultipartFile jar) { + if (jar == null) { + return null; + } + File testDir = new File(JAR_FILE_DIR); + if (!testDir.exists()) { + testDir.mkdirs(); + } + String filePath = testDir + "/" + jar.getOriginalFilename(); + File file = new File(filePath); + try (InputStream in = jar.getInputStream(); OutputStream out = new FileOutputStream(file)) { + file.createNewFile(); + FileUtil.copyStream(in, out); + } catch (IOException e) { + LogUtil.error(e); + MSException.throwException(Translator.get("upload_fail")); + } + return filePath; + } + + private void checkExist(JarConfig jarConfig) { + if (jarConfig.getName() != null) { + JarConfigExample example = new JarConfigExample(); + JarConfigExample.Criteria criteria = example.createCriteria(); + criteria.andNameEqualTo(jarConfig.getName()); + if (StringUtils.isNotBlank(jarConfig.getId())) { + criteria.andIdNotEqualTo(jarConfig.getId()); + } + if (jarConfigMapper.selectByExample(example).size() > 0) { + MSException.throwException(Translator.get("already_exists")); + } + } + } +} diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java index 5c61abc8a3..d2e899d700 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java @@ -15,8 +15,11 @@ import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.member.QueryMemberRequest; +import io.metersphere.notice.domain.MessageDetail; +import io.metersphere.notice.domain.MessageSettingDetail; import io.metersphere.notice.service.DingTaskService; import io.metersphere.notice.service.MailService; +import io.metersphere.notice.service.NoticeService; import io.metersphere.notice.service.WxChatTaskService; import io.metersphere.service.UserService; import io.metersphere.track.dto.TestCaseReviewDTO; @@ -77,6 +80,8 @@ public class TestCaseReviewService { DingTaskService dingTaskService; @Resource WxChatTaskService wxChatTaskService; + @Resource + NoticeService noticeService; public void saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) { checkCaseReviewExist(reviewRequest); @@ -105,14 +110,18 @@ public class TestCaseReviewService { reviewRequest.setStatus(TestCaseReviewStatus.Prepare.name()); testCaseReviewMapper.insert(reviewRequest); String context = getReviewContext(reviewRequest, "create"); + MessageSettingDetail messageSettingDetail = noticeService.searchMessage(); + List reviewTasklist = messageSettingDetail.getReviewTask(); + try { - if (StringUtils.equals(NoticeConstants.NAIL_ROBOT, "NAIL_ROBOT")) { + mailService.sendReviewerNotice(userIds, reviewRequest); + /* if (StringUtils.equals(NoticeConstants.NAIL_ROBOT, "NAIL_ROBOT")) { dingTaskService.sendDingTask(context, userIds); } else if (StringUtils.equals(NoticeConstants.WECHAT_ROBOT, "WECHAT_ROBOT")) { wxChatTaskService.enterpriseWechatTask(); } else { mailService.sendReviewerNotice(userIds, reviewRequest); - } + }*/ } catch (Exception e) { LogUtil.error(e); } diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index ee74568be0..cf6b065263 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit ee74568be0beba46da19616f5832e83f9164c688 +Subproject commit cf6b06526324326a563d933e07118fac014a63b4 diff --git a/backend/src/main/java/org/apache/jmeter/NewDriver.java b/backend/src/main/java/org/apache/jmeter/NewDriver.java new file mode 100644 index 0000000000..32d383f3f0 --- /dev/null +++ b/backend/src/main/java/org/apache/jmeter/NewDriver.java @@ -0,0 +1,387 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.jmeter; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * Main class for JMeter - sets up initial classpath and the loader. + * + */ +public final class NewDriver { + + private static final String CLASSPATH_SEPARATOR = File.pathSeparator; + + private static final String OS_NAME = System.getProperty("os.name");// $NON-NLS-1$ + + private static final String OS_NAME_LC = OS_NAME.toLowerCase(java.util.Locale.ENGLISH); + + private static final String JAVA_CLASS_PATH = "java.class.path";// $NON-NLS-1$ + + private static final String JMETER_LOGFILE_SYSTEM_PROPERTY = "jmeter.logfile";// $NON-NLS-1$ + + private static final String HEADLESS_MODE_PROPERTY = "java.awt.headless";// $NON-NLS-1$ + /** The class loader to use for loading JMeter classes. */ + private static final DynamicClassLoader loader; + + /** The directory JMeter is installed in. */ + private static final String JMETER_INSTALLATION_DIRECTORY; + + private static final List EXCEPTIONS_IN_INIT = new ArrayList<>(); + + // 将当前类加载器设置为 loader ,解决由系统类加载器加载的 JMeter 无法动态加载 jar 包问题 + public static void setContextClassLoader() { + Thread.currentThread().setContextClassLoader(loader); + } + + static { + final List jars = new LinkedList<>(); + final String initiaClasspath = System.getProperty(JAVA_CLASS_PATH); + + // Find JMeter home dir from the initial classpath + String tmpDir; + StringTokenizer tok = new StringTokenizer(initiaClasspath, File.pathSeparator); + if (tok.countTokens() == 1 + || (tok.countTokens() == 2 // Java on Mac OS can add a second entry to the initial classpath + && OS_NAME_LC.startsWith("mac os x")// $NON-NLS-1$ + ) + ) { + File jar = new File(tok.nextToken()); + try { + tmpDir = jar.getCanonicalFile().getParentFile().getParent(); + } catch (IOException e) { + tmpDir = null; + } + } else {// e.g. started from IDE with full classpath + tmpDir = System.getProperty("jmeter.home","");// Allow override $NON-NLS-1$ $NON-NLS-2$ + if (tmpDir.length() == 0) { + File userDir = new File(System.getProperty("user.dir"));// $NON-NLS-1$ + tmpDir = userDir.getAbsoluteFile().getParent(); + } + } + JMETER_INSTALLATION_DIRECTORY=tmpDir; + + /* + * Does the system support UNC paths? If so, may need to fix them up + * later + */ + boolean usesUNC = OS_NAME_LC.startsWith("windows");// $NON-NLS-1$ + + // Add standard jar locations to initial classpath + StringBuilder classpath = new StringBuilder(); + File[] libDirs = new File[] { new File(JMETER_INSTALLATION_DIRECTORY + File.separator + "lib"),// $NON-NLS-1$ $NON-NLS-2$ + new File(JMETER_INSTALLATION_DIRECTORY + File.separator + "lib" + File.separator + "ext"),// $NON-NLS-1$ $NON-NLS-2$ + new File(JMETER_INSTALLATION_DIRECTORY + File.separator + "lib" + File.separator + "junit")};// $NON-NLS-1$ $NON-NLS-2$ + for (File libDir : libDirs) { + File[] libJars = libDir.listFiles((dir, name) -> name.endsWith(".jar")); + if (libJars == null) { + new Throwable("Could not access " + libDir).printStackTrace(); // NOSONAR No logging here + continue; + } + Arrays.sort(libJars); // Bug 50708 Ensure predictable order of jars + for (File libJar : libJars) { + try { + String s = libJar.getPath(); + + // Fix path to allow the use of UNC URLs + if (usesUNC) { + if (s.startsWith("\\\\") && !s.startsWith("\\\\\\")) {// $NON-NLS-1$ $NON-NLS-2$ + s = "\\\\" + s;// $NON-NLS-1$ + } else if (s.startsWith("//") && !s.startsWith("///")) {// $NON-NLS-1$ $NON-NLS-2$ + s = "//" + s;// $NON-NLS-1$ + } + } // usesUNC + + jars.add(new File(s).toURI().toURL());// See Java bug 4496398 + classpath.append(CLASSPATH_SEPARATOR); + classpath.append(s); + } catch (MalformedURLException e) { // NOSONAR + EXCEPTIONS_IN_INIT.add(new Exception("Error adding jar:"+libJar.getAbsolutePath(), e)); + } + } + } + + // ClassFinder needs the classpath + System.setProperty(JAVA_CLASS_PATH, initiaClasspath + classpath.toString()); + loader = AccessController.doPrivileged( + (PrivilegedAction) () -> + new DynamicClassLoader(jars.toArray(new URL[jars.size()])) + ); + } + + /** + * Prevent instantiation. + */ + private NewDriver() { + } + + /** + * Generate an array of jar files located in a directory. + * Jar files located in sub directories will not be added. + * + * @param dir to search for the jar files. + */ + private static File[] listJars(File dir) { + if (dir.isDirectory()) { + return dir.listFiles((f, name) -> { + if (name.endsWith(".jar")) {// $NON-NLS-1$ + File jar = new File(f, name); + return jar.isFile() && jar.canRead(); + } + return false; + }); + } + return new File[0]; + } + + /** + * Add a URL to the loader classpath only; does not update the system classpath. + * + * @param path to be added. + * @throws MalformedURLException when path points to an invalid url + */ + public static void addURL(String path) throws MalformedURLException { + File furl = new File(path); + loader.addURL(furl.toURI().toURL()); // See Java bug 4496398 + File[] jars = listJars(furl); + for (File jar : jars) { + loader.addURL(jar.toURI().toURL()); // See Java bug 4496398 + } + } + + /** + * Add a URL to the loader classpath only; does not update the system + * classpath. + * + * @param url + * The {@link URL} to add to the classpath + */ + public static void addURL(URL url) { + loader.addURL(url); + } + + /** + * Add a directory or jar to the loader and system classpaths. + * + * @param path + * to add to the loader and system classpath + * @throws MalformedURLException + * if path can not be transformed to a valid + * {@link URL} + */ + public static void addPath(String path) throws MalformedURLException { + File file = new File(path); + // Ensure that directory URLs end in "/" + if (file.isDirectory() && !path.endsWith("/")) {// $NON-NLS-1$ + file = new File(path + "/");// $NON-NLS-1$ + } + loader.addURL(file.toURI().toURL()); // See Java bug 4496398 + StringBuilder sb = new StringBuilder(System.getProperty(JAVA_CLASS_PATH)); + sb.append(CLASSPATH_SEPARATOR); + sb.append(path); + File[] jars = listJars(file); + for (File jar : jars) { + loader.addURL(jar.toURI().toURL()); // See Java bug 4496398 + sb.append(CLASSPATH_SEPARATOR); + sb.append(jar.getPath()); + } + + // ClassFinder needs this + System.setProperty(JAVA_CLASS_PATH,sb.toString()); + } + + /** + * Get the directory where JMeter is installed. This is the absolute path + * name. + * + * @return the directory where JMeter is installed. + */ + public static String getJMeterDir() { + return JMETER_INSTALLATION_DIRECTORY; + } + + /** + * The main program which actually runs JMeter. + * + * @param args + * the command line arguments + */ + public static void main(String[] args) { + if(!EXCEPTIONS_IN_INIT.isEmpty()) { + System.err.println("Configuration error during init, see exceptions:"+exceptionsToString(EXCEPTIONS_IN_INIT)); // NOSONAR Intentional System.err use + } else { + Thread.currentThread().setContextClassLoader(loader); + + + setLoggingProperties(args); + + try { + // Only set property if it has not been set explicitely + if(System.getProperty(HEADLESS_MODE_PROPERTY) == null && shouldBeHeadless(args)) { + System.setProperty(HEADLESS_MODE_PROPERTY, "true"); + } + Class initialClass = loader.loadClass("org.apache.jmeter.JMeter");// $NON-NLS-1$ + Object instance = initialClass.getDeclaredConstructor().newInstance(); + Method startup = initialClass.getMethod("start", new Class[] { new String[0].getClass() });// $NON-NLS-1$ + startup.invoke(instance, new Object[] { args }); + } catch(Throwable e){ // NOSONAR We want to log home directory in case of exception + e.printStackTrace(); // NOSONAR No logger at this step + System.err.println("JMeter home directory was detected as: "+JMETER_INSTALLATION_DIRECTORY); // NOSONAR Intentional System.err use + } + } + } + + /** + * @param exceptionsInInit List of {@link Exception} + * @return String + */ + private static String exceptionsToString(List exceptionsInInit) { + StringBuilder builder = new StringBuilder(); + for (Exception exception : exceptionsInInit) { + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + exception.printStackTrace(printWriter); // NOSONAR + builder.append(stringWriter.toString()) + .append("\r\n"); + } + return builder.toString(); + } + + /* + * Set logging related system properties. + */ + private static void setLoggingProperties(String[] args) { + String jmLogFile = getCommandLineArgument(args, 'j', "jmeterlogfile");// $NON-NLS-1$ $NON-NLS-2$ + + if (jmLogFile != null && !jmLogFile.isEmpty()) { + jmLogFile = replaceDateFormatInFileName(jmLogFile); + System.setProperty(JMETER_LOGFILE_SYSTEM_PROPERTY, jmLogFile);// $NON-NLS-1$ + } else if (System.getProperty(JMETER_LOGFILE_SYSTEM_PROPERTY) == null) {// $NON-NLS-1$ + System.setProperty(JMETER_LOGFILE_SYSTEM_PROPERTY, "jmeter.log");// $NON-NLS-1$ $NON-NLS-2$ + } + + String jmLogConf = getCommandLineArgument(args, 'i', "jmeterlogconf");// $NON-NLS-1$ $NON-NLS-2$ + File logConfFile = null; + + if (jmLogConf != null && !jmLogConf.isEmpty()) { + logConfFile = new File(jmLogConf); + } else if (System.getProperty("log4j.configurationFile") == null) {// $NON-NLS-1$ + logConfFile = new File("log4j2.xml");// $NON-NLS-1$ + if (!logConfFile.isFile()) { + logConfFile = new File(JMETER_INSTALLATION_DIRECTORY, "bin" + File.separator + "log4j2.xml");// $NON-NLS-1$ $NON-NLS-2$ + } + } + + if (logConfFile != null) { + System.setProperty("log4j.configurationFile", logConfFile.toURI().toString());// $NON-NLS-1$ + } + } + + private static boolean shouldBeHeadless(String[] args) { + for (String arg : args) { + if("-n".equals(arg) || "-s".equals(arg) || "-g".equals(arg)) { + return true; + } + } + return false; + } + /* + * Find command line argument option value by the id and name. + */ + private static String getCommandLineArgument(String[] args, int id, String name) { + final String shortArgName = "-" + ((char) id);// $NON-NLS-1$ + final String longArgName = "--" + name;// $NON-NLS-1$ + + String value = null; + + for (int i = 0; i < args.length; i++) { + if ((shortArgName.equals(args[i]) && i < args.length - 1) + || longArgName.equals(args[i])) { + if (!args[i + 1].startsWith("-")) {// $NON-NLS-1$ + value = args[i + 1]; + } + break; + } else if (!shortArgName.equals(args[i]) && args[i].startsWith(shortArgName)) { + value = args[i].substring(shortArgName.length()); + break; + } + } + + return value; + } + + /* + * If the fileName contains at least one set of paired single-quotes, reformat using DateFormat + */ + private static String replaceDateFormatInFileName(String fileName) { + try { + StringBuilder builder = new StringBuilder(); + + final Date date = new Date(); + int fromIndex = 0; + int begin = fileName.indexOf('\'', fromIndex);// $NON-NLS-1$ + int end; + + String format; + SimpleDateFormat dateFormat; + + while (begin != -1) { + builder.append(fileName.substring(fromIndex, begin)); + + fromIndex = begin + 1; + end = fileName.indexOf('\'', fromIndex);// $NON-NLS-1$ + if (end == -1) { + throw new IllegalArgumentException("Invalid pairs of single-quotes in the file name: " + fileName);// $NON-NLS-1$ + } + + format = fileName.substring(begin + 1, end); + dateFormat = new SimpleDateFormat(format); + builder.append(dateFormat.format(date)); + + fromIndex = end + 1; + begin = fileName.indexOf('\'', fromIndex);// $NON-NLS-1$ + } + + if (fromIndex < fileName.length() - 1) { + builder.append(fileName.substring(fromIndex)); + } + + return builder.toString(); + } catch (Exception ex) { + System.err.println("Error replacing date format in file name:"+fileName+", error:"+ex.getMessage()); // NOSONAR + } + + return fileName; + } +} diff --git a/backend/src/main/resources/db/migration/V31__message_task.sql b/backend/src/main/resources/db/migration/V31__message_task.sql index e7c6e59c7a..5b0d14bddd 100644 --- a/backend/src/main/resources/db/migration/V31__message_task.sql +++ b/backend/src/main/resources/db/migration/V31__message_task.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS message_task ( event varchar(255) NOT NULL COMMENT '通知事件类型', user_id varchar(50) NOT NULL COMMENT '接收人id', task_type varchar(64) NOT NULL, - webhook varchar(255) NOT NULL COMMENT 'webhook地址', + webhook varchar(255) COMMENT 'webhook地址', CONSTRAINT message_manage_pk PRIMARY KEY (id) ) diff --git a/backend/src/main/resources/db/migration/V34__api_test_jar.sql b/backend/src/main/resources/db/migration/V34__api_test_jar.sql new file mode 100644 index 0000000000..b6bc46c2e6 --- /dev/null +++ b/backend/src/main/resources/db/migration/V34__api_test_jar.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS `jar_config` ( + `id` varchar(50) NOT NULL COMMENT 'ID', + `name` varchar(64) NOT NULL COMMENT 'Name', + `file_name` varchar(64) NOT NULL COMMENT 'File name', + `creator` varchar(50) NOT NULL COMMENT 'creator User ID', + `modifier` varchar(50) NOT NULL COMMENT 'Modifier User ID', + `path` varchar(255) NOT NULL COMMENT 'File path', + `enable` tinyint(1) COMMENT 'Config enable', + `description` varchar(255) DEFAULT NULL COMMENT 'description', + `create_time` bigint(13) NOT NULL COMMENT 'Create timestamp', + `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp', + PRIMARY KEY (`id`) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; \ No newline at end of file diff --git a/backend/src/main/resources/generatorConfig.xml b/backend/src/main/resources/generatorConfig.xml index 404c24f5d6..a2b8b4801c 100644 --- a/backend/src/main/resources/generatorConfig.xml +++ b/backend/src/main/resources/generatorConfig.xml @@ -68,6 +68,5 @@
- \ No newline at end of file diff --git a/frontend/src/business/components/api/test/ApiTestConfig.vue b/frontend/src/business/components/api/test/ApiTestConfig.vue index bde0fd0817..b53019010a 100644 --- a/frontend/src/business/components/api/test/ApiTestConfig.vue +++ b/frontend/src/business/components/api/test/ApiTestConfig.vue @@ -40,6 +40,9 @@ {{ $t('api_report.title') }} + + {{ $t('api_test.jar_config.title') }} + {{ $t('api_test.create_performance_test') }} @@ -58,6 +61,9 @@ + + + + +
+ + +
+
+ + + + + diff --git a/frontend/src/business/components/api/test/components/jar/JarConfigFrom.vue b/frontend/src/business/components/api/test/components/jar/JarConfigFrom.vue new file mode 100644 index 0000000000..2698d8c221 --- /dev/null +++ b/frontend/src/business/components/api/test/components/jar/JarConfigFrom.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/frontend/src/business/components/api/test/components/jar/JarConfigList.vue b/frontend/src/business/components/api/test/components/jar/JarConfigList.vue new file mode 100644 index 0000000000..2632b7b29a --- /dev/null +++ b/frontend/src/business/components/api/test/components/jar/JarConfigList.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/frontend/src/business/components/performance/test/EditPerformanceTestPlan.vue b/frontend/src/business/components/performance/test/EditPerformanceTestPlan.vue index 29096c205c..8eebd7108d 100644 --- a/frontend/src/business/components/performance/test/EditPerformanceTestPlan.vue +++ b/frontend/src/business/components/performance/test/EditPerformanceTestPlan.vue @@ -125,6 +125,8 @@ export default { this.isReadOnly = true; } this.getTest(this.$route.params.testId); + }, + activated() { this.listProjects(); }, mounted() { diff --git a/frontend/src/business/components/project/MsProject.vue b/frontend/src/business/components/project/MsProject.vue index 57c583877a..4974ec98c3 100644 --- a/frontend/src/business/components/project/MsProject.vue +++ b/frontend/src/business/components/project/MsProject.vue @@ -37,7 +37,7 @@ @@ -76,6 +76,7 @@ + diff --git a/frontend/src/business/components/settings/organization/TaskNotification.vue b/frontend/src/business/components/settings/organization/TaskNotification.vue index fac0df555f..38b1b360cb 100644 --- a/frontend/src/business/components/settings/organization/TaskNotification.vue +++ b/frontend/src/business/components/settings/organization/TaskNotification.vue @@ -26,7 +26,7 @@ >