diff --git a/.gitignore b/.gitignore index 2aab7a0393..832cb0b18e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ target .settings .project .classpath +.jython_cache \ No newline at end of file diff --git a/README.md b/README.md index 0d4c145cd5..207963ad02 100755 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟 ## UI 展示 -![UI](https://metersphere.io/images/screenshot/ss07.png) +![UI](https://metersphere.io/images/screenshot/ss01.png) ## 在线体验 - 环境地址:https://demo.metersphere.com/ @@ -49,6 +49,10 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu - [完整文档](https://metersphere.io/docs/) - [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4) +## MeterSphere 企业版 +[申请企业版使用](https://jinshuju.net/f/CzzAOe) +> 注: 企业版支持离线安装,申请通过后会提供高速下载链接 + ## 相关工具 - [Jenkins 插件](https://github.com/metersphere/jenkins-plugin) diff --git a/backend/pom.xml b/backend/pom.xml index ab5270911f..d0ce558dd6 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -153,6 +153,12 @@ + + org.python + jython + 2.7.2 + + org.apache.jmeter ApacheJMeter_functions @@ -207,13 +213,7 @@ com.fit2cloud quartz-spring-boot-starter - - - org.springframework.boot - spring-boot-autoconfigure - - - 0.0.4 + 0.0.7 diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java b/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java index 96a911e582..ed50eebd11 100644 --- a/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java @@ -12,6 +12,7 @@ public class KeyValue { private String type; private List files; private String description; + private boolean enable; public KeyValue() { } diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223PostProcessor.java b/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223PostProcessor.java new file mode 100644 index 0000000000..c9d9f7dea7 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223PostProcessor.java @@ -0,0 +1,10 @@ +package io.metersphere.api.dto.scenario.processor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class JSR223PostProcessor extends JSR223Processor { + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223PreProcessor.java b/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223PreProcessor.java new file mode 100644 index 0000000000..8192327b8a --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223PreProcessor.java @@ -0,0 +1,10 @@ +package io.metersphere.api.dto.scenario.processor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class JSR223PreProcessor extends JSR223Processor { + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223Processor.java b/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223Processor.java new file mode 100644 index 0000000000..2520a04c4a --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/processor/JSR223Processor.java @@ -0,0 +1,9 @@ +package io.metersphere.api.dto.scenario.processor; + +import lombok.Data; + +@Data +public class JSR223Processor { + private String script; + private String language; +} diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/request/DubboRequest.java b/backend/src/main/java/io/metersphere/api/dto/scenario/request/DubboRequest.java index 73322cfef0..48398edb1c 100644 --- a/backend/src/main/java/io/metersphere/api/dto/scenario/request/DubboRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/request/DubboRequest.java @@ -8,6 +8,8 @@ import io.metersphere.api.dto.scenario.assertions.Assertions; import io.metersphere.api.dto.scenario.extract.Extract; import io.metersphere.api.dto.scenario.processor.BeanShellPostProcessor; import io.metersphere.api.dto.scenario.processor.BeanShellPreProcessor; +import io.metersphere.api.dto.scenario.processor.JSR223PostProcessor; +import io.metersphere.api.dto.scenario.processor.JSR223PreProcessor; import io.metersphere.api.dto.scenario.request.dubbo.ConfigCenter; import io.metersphere.api.dto.scenario.request.dubbo.ConsumerAndService; import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter; @@ -53,4 +55,8 @@ public class DubboRequest implements Request { private BeanShellPostProcessor beanShellPostProcessor; @JSONField(ordinal = 14) private Boolean enable; + @JSONField(ordinal = 15) + private JSR223PreProcessor jsr223PreProcessor; + @JSONField(ordinal = 16) + private JSR223PostProcessor jsr223PostProcessor; } diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/request/HttpRequest.java b/backend/src/main/java/io/metersphere/api/dto/scenario/request/HttpRequest.java index 1b83ab850d..dc0ffde3c8 100644 --- a/backend/src/main/java/io/metersphere/api/dto/scenario/request/HttpRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/request/HttpRequest.java @@ -8,6 +8,8 @@ import io.metersphere.api.dto.scenario.assertions.Assertions; import io.metersphere.api.dto.scenario.extract.Extract; import io.metersphere.api.dto.scenario.processor.BeanShellPostProcessor; import io.metersphere.api.dto.scenario.processor.BeanShellPreProcessor; +import io.metersphere.api.dto.scenario.processor.JSR223PostProcessor; +import io.metersphere.api.dto.scenario.processor.JSR223PreProcessor; import lombok.Data; import java.util.List; @@ -49,4 +51,10 @@ public class HttpRequest implements Request { private Long connectTimeout; @JSONField(ordinal = 15) private Long responseTimeout; + @JSONField(ordinal = 16) + private Boolean followRedirects; + @JSONField(ordinal = 17) + private JSR223PreProcessor jsr223PreProcessor; + @JSONField(ordinal = 18) + private JSR223PostProcessor jsr223PostProcessor; } 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 48ba7fe65e..45e177624d 100644 --- a/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java +++ b/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java @@ -11,6 +11,8 @@ import org.apache.jmeter.save.SaveService; import org.apache.jmeter.util.JMeterUtils; import org.apache.jmeter.visualizers.backend.BackendListener; import org.apache.jorphan.collections.HashTree; +import org.python.core.Options; +import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -30,6 +32,12 @@ public class JMeterService { String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties"; JMeterUtils.loadJMeterProperties(JMETER_PROPERTIES); JMeterUtils.setJMeterHome(JMETER_HOME); + JMeterUtils.setLocale(LocaleContextHolder.getLocale()); + + + //解决无法加载 PyScriptEngineFactory + Options.importSite = false; + try { Object scriptWrapper = SaveService.loadElement(is); HashTree testPlan = getHashTree(scriptWrapper); diff --git a/backend/src/main/java/io/metersphere/api/parse/JmeterDocumentParser.java b/backend/src/main/java/io/metersphere/api/parse/JmeterDocumentParser.java index 253ae0ff6d..efa1771c8c 100644 --- a/backend/src/main/java/io/metersphere/api/parse/JmeterDocumentParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/JmeterDocumentParser.java @@ -157,7 +157,7 @@ public class JmeterDocumentParser { u += k + "=" + ScriptEngineUtils.calculate(v); return u; }); - ele.setTextContent(url + params); + ele.setTextContent(url + ((params != null && !params.equals("?")) ? params : "")); break; case "Argument.value": String textContent = ele.getTextContent(); diff --git a/backend/src/main/java/io/metersphere/base/domain/ApiTestEnvironmentWithBLOBs.java b/backend/src/main/java/io/metersphere/base/domain/ApiTestEnvironmentWithBLOBs.java index 8c9a7ddb5d..363762f824 100644 --- a/backend/src/main/java/io/metersphere/base/domain/ApiTestEnvironmentWithBLOBs.java +++ b/backend/src/main/java/io/metersphere/base/domain/ApiTestEnvironmentWithBLOBs.java @@ -1,10 +1,11 @@ package io.metersphere.base.domain; -import java.io.Serializable; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import java.io.Serializable; + @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @@ -15,5 +16,6 @@ public class ApiTestEnvironmentWithBLOBs extends ApiTestEnvironment implements S private String customData; + private String hosts; private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/Notice.java b/backend/src/main/java/io/metersphere/base/domain/Notice.java new file mode 100644 index 0000000000..3096905b54 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/Notice.java @@ -0,0 +1,19 @@ +package io.metersphere.base.domain; + +import java.io.Serializable; +import lombok.Data; + +@Data +public class Notice implements Serializable { + private String event; + + private String testId; + + private String name; + + private String email; + + private String enable; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/NoticeExample.java b/backend/src/main/java/io/metersphere/base/domain/NoticeExample.java new file mode 100644 index 0000000000..faee41158a --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/NoticeExample.java @@ -0,0 +1,550 @@ +package io.metersphere.base.domain; + +import java.util.ArrayList; +import java.util.List; + +public class NoticeExample { + protected String orderByClause; + + protected boolean distinct; + + protected List oredCriteria; + + public NoticeExample() { + 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 andEventIsNull() { + addCriterion("EVENT is null"); + return (Criteria) this; + } + + public Criteria andEventIsNotNull() { + addCriterion("EVENT is not null"); + return (Criteria) this; + } + + public Criteria andEventEqualTo(String value) { + addCriterion("EVENT =", value, "event"); + return (Criteria) this; + } + + public Criteria andEventNotEqualTo(String value) { + addCriterion("EVENT <>", value, "event"); + return (Criteria) this; + } + + public Criteria andEventGreaterThan(String value) { + addCriterion("EVENT >", value, "event"); + return (Criteria) this; + } + + public Criteria andEventGreaterThanOrEqualTo(String value) { + addCriterion("EVENT >=", value, "event"); + return (Criteria) this; + } + + public Criteria andEventLessThan(String value) { + addCriterion("EVENT <", value, "event"); + return (Criteria) this; + } + + public Criteria andEventLessThanOrEqualTo(String value) { + addCriterion("EVENT <=", value, "event"); + return (Criteria) this; + } + + public Criteria andEventLike(String value) { + addCriterion("EVENT like", value, "event"); + return (Criteria) this; + } + + public Criteria andEventNotLike(String value) { + addCriterion("EVENT not like", value, "event"); + return (Criteria) this; + } + + public Criteria andEventIn(List values) { + addCriterion("EVENT in", values, "event"); + return (Criteria) this; + } + + public Criteria andEventNotIn(List values) { + addCriterion("EVENT not in", values, "event"); + return (Criteria) this; + } + + public Criteria andEventBetween(String value1, String value2) { + addCriterion("EVENT between", value1, value2, "event"); + return (Criteria) this; + } + + public Criteria andEventNotBetween(String value1, String value2) { + addCriterion("EVENT not between", value1, value2, "event"); + return (Criteria) this; + } + + public Criteria andTestIdIsNull() { + addCriterion("TEST_ID is null"); + return (Criteria) this; + } + + public Criteria andTestIdIsNotNull() { + addCriterion("TEST_ID is not null"); + return (Criteria) this; + } + + public Criteria andTestIdEqualTo(String value) { + addCriterion("TEST_ID =", value, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdNotEqualTo(String value) { + addCriterion("TEST_ID <>", value, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdGreaterThan(String value) { + addCriterion("TEST_ID >", value, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdGreaterThanOrEqualTo(String value) { + addCriterion("TEST_ID >=", value, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdLessThan(String value) { + addCriterion("TEST_ID <", value, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdLessThanOrEqualTo(String value) { + addCriterion("TEST_ID <=", value, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdLike(String value) { + addCriterion("TEST_ID like", value, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdNotLike(String value) { + addCriterion("TEST_ID not like", value, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdIn(List values) { + addCriterion("TEST_ID in", values, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdNotIn(List values) { + addCriterion("TEST_ID not in", values, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdBetween(String value1, String value2) { + addCriterion("TEST_ID between", value1, value2, "testId"); + return (Criteria) this; + } + + public Criteria andTestIdNotBetween(String value1, String value2) { + addCriterion("TEST_ID not between", value1, value2, "testId"); + 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 andEmailIsNull() { + addCriterion("EMAIL is null"); + return (Criteria) this; + } + + public Criteria andEmailIsNotNull() { + addCriterion("EMAIL is not null"); + return (Criteria) this; + } + + public Criteria andEmailEqualTo(String value) { + addCriterion("EMAIL =", value, "email"); + return (Criteria) this; + } + + public Criteria andEmailNotEqualTo(String value) { + addCriterion("EMAIL <>", value, "email"); + return (Criteria) this; + } + + public Criteria andEmailGreaterThan(String value) { + addCriterion("EMAIL >", value, "email"); + return (Criteria) this; + } + + public Criteria andEmailGreaterThanOrEqualTo(String value) { + addCriterion("EMAIL >=", value, "email"); + return (Criteria) this; + } + + public Criteria andEmailLessThan(String value) { + addCriterion("EMAIL <", value, "email"); + return (Criteria) this; + } + + public Criteria andEmailLessThanOrEqualTo(String value) { + addCriterion("EMAIL <=", value, "email"); + return (Criteria) this; + } + + public Criteria andEmailLike(String value) { + addCriterion("EMAIL like", value, "email"); + return (Criteria) this; + } + + public Criteria andEmailNotLike(String value) { + addCriterion("EMAIL not like", value, "email"); + return (Criteria) this; + } + + public Criteria andEmailIn(List values) { + addCriterion("EMAIL in", values, "email"); + return (Criteria) this; + } + + public Criteria andEmailNotIn(List values) { + addCriterion("EMAIL not in", values, "email"); + return (Criteria) this; + } + + public Criteria andEmailBetween(String value1, String value2) { + addCriterion("EMAIL between", value1, value2, "email"); + return (Criteria) this; + } + + public Criteria andEmailNotBetween(String value1, String value2) { + addCriterion("EMAIL not between", value1, value2, "email"); + 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(String value) { + addCriterion("`ENABLE` =", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableNotEqualTo(String value) { + addCriterion("`ENABLE` <>", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableGreaterThan(String value) { + addCriterion("`ENABLE` >", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableGreaterThanOrEqualTo(String value) { + addCriterion("`ENABLE` >=", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableLessThan(String value) { + addCriterion("`ENABLE` <", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableLessThanOrEqualTo(String value) { + addCriterion("`ENABLE` <=", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableLike(String value) { + addCriterion("`ENABLE` like", value, "enable"); + return (Criteria) this; + } + + public Criteria andEnableNotLike(String value) { + addCriterion("`ENABLE` not like", 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(String value1, String value2) { + addCriterion("`ENABLE` between", value1, value2, "enable"); + return (Criteria) this; + } + + public Criteria andEnableNotBetween(String value1, String value2) { + addCriterion("`ENABLE` not between", value1, value2, "enable"); + 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/domain/TestPlanProject.java b/backend/src/main/java/io/metersphere/base/domain/TestPlanProject.java new file mode 100644 index 0000000000..cc92cf7c5a --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/TestPlanProject.java @@ -0,0 +1,13 @@ +package io.metersphere.base.domain; + +import java.io.Serializable; +import lombok.Data; + +@Data +public class TestPlanProject implements Serializable { + private String testPlanId; + + private String projectId; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/TestPlanProjectExample.java b/backend/src/main/java/io/metersphere/base/domain/TestPlanProjectExample.java new file mode 100644 index 0000000000..38ec8d78aa --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/TestPlanProjectExample.java @@ -0,0 +1,340 @@ +package io.metersphere.base.domain; + +import java.util.ArrayList; +import java.util.List; + +public class TestPlanProjectExample { + protected String orderByClause; + + protected boolean distinct; + + protected List oredCriteria; + + public TestPlanProjectExample() { + 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 andTestPlanIdIsNull() { + addCriterion("test_plan_id is null"); + return (Criteria) this; + } + + public Criteria andTestPlanIdIsNotNull() { + addCriterion("test_plan_id is not null"); + return (Criteria) this; + } + + public Criteria andTestPlanIdEqualTo(String value) { + addCriterion("test_plan_id =", value, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdNotEqualTo(String value) { + addCriterion("test_plan_id <>", value, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdGreaterThan(String value) { + addCriterion("test_plan_id >", value, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdGreaterThanOrEqualTo(String value) { + addCriterion("test_plan_id >=", value, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdLessThan(String value) { + addCriterion("test_plan_id <", value, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdLessThanOrEqualTo(String value) { + addCriterion("test_plan_id <=", value, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdLike(String value) { + addCriterion("test_plan_id like", value, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdNotLike(String value) { + addCriterion("test_plan_id not like", value, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdIn(List values) { + addCriterion("test_plan_id in", values, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdNotIn(List values) { + addCriterion("test_plan_id not in", values, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdBetween(String value1, String value2) { + addCriterion("test_plan_id between", value1, value2, "testPlanId"); + return (Criteria) this; + } + + public Criteria andTestPlanIdNotBetween(String value1, String value2) { + addCriterion("test_plan_id not between", value1, value2, "testPlanId"); + return (Criteria) this; + } + + public Criteria andProjectIdIsNull() { + addCriterion("project_id is null"); + return (Criteria) this; + } + + public Criteria andProjectIdIsNotNull() { + addCriterion("project_id is not null"); + return (Criteria) this; + } + + public Criteria andProjectIdEqualTo(String value) { + addCriterion("project_id =", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotEqualTo(String value) { + addCriterion("project_id <>", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdGreaterThan(String value) { + addCriterion("project_id >", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdGreaterThanOrEqualTo(String value) { + addCriterion("project_id >=", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLessThan(String value) { + addCriterion("project_id <", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLessThanOrEqualTo(String value) { + addCriterion("project_id <=", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLike(String value) { + addCriterion("project_id like", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotLike(String value) { + addCriterion("project_id not like", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdIn(List values) { + addCriterion("project_id in", values, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotIn(List values) { + addCriterion("project_id not in", values, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdBetween(String value1, String value2) { + addCriterion("project_id between", value1, value2, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotBetween(String value1, String value2) { + addCriterion("project_id not between", value1, value2, "projectId"); + 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/ApiTestEnvironmentMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ApiTestEnvironmentMapper.xml index 16a8f7a075..8e2e5ebe45 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiTestEnvironmentMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiTestEnvironmentMapper.xml @@ -14,6 +14,7 @@ + @@ -77,7 +78,7 @@ id, `name`, project_id, protocol, socket, `domain`, port - `variables`, headers, custom_data + `variables`, headers, custom_data,hosts @@ -243,6 +251,9 @@ custom_data = #{record.customData,jdbcType=LONGVARCHAR}, + + hosts = #{hosts,jdbcType=LONGVARCHAR}, + @@ -259,7 +270,8 @@ port = #{record.port,jdbcType=INTEGER}, `variables` = #{record.variables,jdbcType=LONGVARCHAR}, headers = #{record.headers,jdbcType=LONGVARCHAR}, - custom_data = #{record.customData,jdbcType=LONGVARCHAR} + custom_data = #{record.customData,jdbcType=LONGVARCHAR}, + hosts = #{hosts,jdbcType=LONGVARCHAR} @@ -307,6 +319,9 @@ custom_data = #{customData,jdbcType=LONGVARCHAR}, + + hosts = #{hosts,jdbcType=LONGVARCHAR}, + where id = #{id,jdbcType=VARCHAR} @@ -320,7 +335,8 @@ port = #{port,jdbcType=INTEGER}, `variables` = #{variables,jdbcType=LONGVARCHAR}, headers = #{headers,jdbcType=LONGVARCHAR}, - custom_data = #{customData,jdbcType=LONGVARCHAR} + custom_data = #{customData,jdbcType=LONGVARCHAR}, + hosts = #{hosts,jdbcType=LONGVARCHAR} where id = #{id,jdbcType=VARCHAR} diff --git a/backend/src/main/java/io/metersphere/base/mapper/NoticeMapper.java b/backend/src/main/java/io/metersphere/base/mapper/NoticeMapper.java new file mode 100644 index 0000000000..4ca41aabdf --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/NoticeMapper.java @@ -0,0 +1,22 @@ +package io.metersphere.base.mapper; + +import io.metersphere.base.domain.Notice; +import io.metersphere.base.domain.NoticeExample; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +public interface NoticeMapper { + long countByExample(NoticeExample example); + + int deleteByExample(NoticeExample example); + + int insert(Notice record); + + int insertSelective(Notice record); + + List selectByExample(NoticeExample example); + + int updateByExampleSelective(@Param("record") Notice record, @Param("example") NoticeExample example); + + int updateByExample(@Param("record") Notice record, @Param("example") NoticeExample example); +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/NoticeMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/NoticeMapper.xml new file mode 100644 index 0000000000..9e59138b2c --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/NoticeMapper.xml @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + 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} + + + + + + + + + + + EVENT, TEST_ID, `NAME`, EMAIL, `ENABLE` + + + + delete from notice + + + + + + insert into notice (EVENT, TEST_ID, `NAME`, + EMAIL, `ENABLE`) + values (#{event,jdbcType=VARCHAR}, #{testId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, + #{email,jdbcType=VARCHAR}, #{enable,jdbcType=VARCHAR}) + + + insert into notice + + + EVENT, + + + TEST_ID, + + + `NAME`, + + + EMAIL, + + + `ENABLE`, + + + + + #{event,jdbcType=VARCHAR}, + + + #{testId,jdbcType=VARCHAR}, + + + #{name,jdbcType=VARCHAR}, + + + #{email,jdbcType=VARCHAR}, + + + #{enable,jdbcType=VARCHAR}, + + + + + + update notice + + + EVENT = #{record.event,jdbcType=VARCHAR}, + + + TEST_ID = #{record.testId,jdbcType=VARCHAR}, + + + `NAME` = #{record.name,jdbcType=VARCHAR}, + + + EMAIL = #{record.email,jdbcType=VARCHAR}, + + + `ENABLE` = #{record.enable,jdbcType=VARCHAR}, + + + + + + + + update notice + set EVENT = #{record.event,jdbcType=VARCHAR}, + TEST_ID = #{record.testId,jdbcType=VARCHAR}, + `NAME` = #{record.name,jdbcType=VARCHAR}, + EMAIL = #{record.email,jdbcType=VARCHAR}, + `ENABLE` = #{record.enable,jdbcType=VARCHAR} + + + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/TestPlanProjectMapper.java b/backend/src/main/java/io/metersphere/base/mapper/TestPlanProjectMapper.java new file mode 100644 index 0000000000..8cc74a97cf --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/TestPlanProjectMapper.java @@ -0,0 +1,22 @@ +package io.metersphere.base.mapper; + +import io.metersphere.base.domain.TestPlanProject; +import io.metersphere.base.domain.TestPlanProjectExample; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +public interface TestPlanProjectMapper { + long countByExample(TestPlanProjectExample example); + + int deleteByExample(TestPlanProjectExample example); + + int insert(TestPlanProject record); + + int insertSelective(TestPlanProject record); + + List selectByExample(TestPlanProjectExample example); + + int updateByExampleSelective(@Param("record") TestPlanProject record, @Param("example") TestPlanProjectExample example); + + int updateByExample(@Param("record") TestPlanProject record, @Param("example") TestPlanProjectExample example); +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/TestPlanProjectMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/TestPlanProjectMapper.xml new file mode 100644 index 0000000000..34bf58bc7c --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/TestPlanProjectMapper.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + 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} + + + + + + + + + + + test_plan_id, project_id + + + + delete from test_plan_project + + + + + + insert into test_plan_project (test_plan_id, project_id) + values (#{testPlanId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}) + + + insert into test_plan_project + + + test_plan_id, + + + project_id, + + + + + #{testPlanId,jdbcType=VARCHAR}, + + + #{projectId,jdbcType=VARCHAR}, + + + + + + update test_plan_project + + + test_plan_id = #{record.testPlanId,jdbcType=VARCHAR}, + + + project_id = #{record.projectId,jdbcType=VARCHAR}, + + + + + + + + update test_plan_project + set test_plan_id = #{record.testPlanId,jdbcType=VARCHAR}, + project_id = #{record.projectId,jdbcType=VARCHAR} + + + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/config/QuartzAutoConfiguration.java b/backend/src/main/java/io/metersphere/config/QuartzAutoConfiguration.java deleted file mode 100644 index 215c2c7ca4..0000000000 --- a/backend/src/main/java/io/metersphere/config/QuartzAutoConfiguration.java +++ /dev/null @@ -1,92 +0,0 @@ -package io.metersphere.config; - -import com.fit2cloud.autoconfigure.QuartzProperties; -import com.fit2cloud.quartz.QuartzInstanceIdGenerator; -import com.fit2cloud.quartz.SchedulerStarter; -import com.fit2cloud.quartz.service.QuartzManageService; -import com.fit2cloud.quartz.util.QuartzBeanFactory; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.quartz.SchedulerFactoryBean; -import org.springframework.util.StringUtils; - -import javax.sql.DataSource; -import java.util.Properties; -import java.util.TimeZone; - -@Configuration -@EnableConfigurationProperties(QuartzProperties.class) -@ConditionalOnClass(DataSource.class) -@AutoConfigureAfter(DataSource.class) -public class QuartzAutoConfiguration { - private DataSource dataSource; - - private QuartzProperties properties; - - public QuartzAutoConfiguration(ObjectProvider dataSourceProvider, QuartzProperties properties) { - this.dataSource = dataSourceProvider.getIfAvailable(); - this.properties = properties; - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true") - public SchedulerStarter schedulerStarter() { - return new SchedulerStarter(); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true") - public QuartzBeanFactory quartzBeanFactory() { - return new QuartzBeanFactory(); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true") - public QuartzManageService quartzManageService() { - return new QuartzManageService(); - } - - @Bean - @ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true") - public TimeZone quartzTimeZone() { - return TimeZone.getTimeZone(properties.getTimeZone()); - } - - @Bean - @ConditionalOnClass(DataSource.class) - @ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true") - public SchedulerFactoryBean clusterSchedulerFactoryBean() { - SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); - schedulerFactoryBean.setDataSource(this.dataSource); - schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContextKey"); - schedulerFactoryBean.setOverwriteExistingJobs(true); - schedulerFactoryBean.setStartupDelay(60);// 60 秒之后开始执行定时任务 - Properties props = new Properties(); - props.put("org.quartz.scheduler.instanceName", "clusterScheduler"); - props.put("org.quartz.scheduler.instanceId", "AUTO"); // 集群下的instanceId 必须唯一 - props.put("org.quartz.scheduler.instanceIdGenerator.class", QuartzInstanceIdGenerator.class.getName());// instanceId 生成的方式 - props.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); - props.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"); - props.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); - props.put("org.quartz.jobStore.isClustered", "true"); - props.put("org.quartz.jobStore.clusterCheckinInterval", "20000"); - props.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); - props.put("org.quartz.threadPool.threadCount", "10"); - props.put("org.quartz.threadPool.threadPriority", "5"); - props.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", "true"); - schedulerFactoryBean.setQuartzProperties(props); - if (!StringUtils.isEmpty(this.properties.getSchedulerName())) { - schedulerFactoryBean.setBeanName(this.properties.getSchedulerName()); - } - return schedulerFactoryBean; - } -} diff --git a/backend/src/main/java/io/metersphere/config/ShiroConfig.java b/backend/src/main/java/io/metersphere/config/ShiroConfig.java index ab1e55c60c..87e63496fa 100644 --- a/backend/src/main/java/io/metersphere/config/ShiroConfig.java +++ b/backend/src/main/java/io/metersphere/config/ShiroConfig.java @@ -102,7 +102,7 @@ public class ShiroConfig implements EnvironmentAware { @Bean public SessionManager sessionManager(MemoryConstrainedCacheManager memoryConstrainedCacheManager) { - Long sessionTimeout = env.getProperty("session.timeout", Long.class, 1800L); // 默认1800s, 半个小时 + Long sessionTimeout = env.getProperty("session.timeout", Long.class, 43200L); // 默认43200s, 12个小时 return ShiroUtils.getSessionManager(sessionTimeout, memoryConstrainedCacheManager); } diff --git a/backend/src/main/java/io/metersphere/excel/utils/EasyExcelExporter.java b/backend/src/main/java/io/metersphere/excel/utils/EasyExcelExporter.java index be802d3bfb..5a6b39fd20 100644 --- a/backend/src/main/java/io/metersphere/excel/utils/EasyExcelExporter.java +++ b/backend/src/main/java/io/metersphere/excel/utils/EasyExcelExporter.java @@ -1,8 +1,11 @@ package io.metersphere.excel.utils; import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import io.metersphere.commons.utils.LogUtil; import io.metersphere.exception.ExcelException; +import org.apache.poi.ss.usermodel.IndexedColors; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -29,9 +32,12 @@ public class EasyExcelExporter { public void export(HttpServletResponse response, List data, String fileName, String sheetName) { response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + contentWriteCellStyle.setWrapped(true); try { + HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(null, contentWriteCellStyle); response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx"); - EasyExcel.write(response.getOutputStream(), this.clazz).sheet(sheetName).doWrite(data); + EasyExcel.write(response.getOutputStream(), this.clazz).registerWriteHandler(horizontalCellStyleStrategy).sheet(sheetName).doWrite(data); } catch (UnsupportedEncodingException e) { LogUtil.error(e.getMessage(), e); throw new ExcelException("Utf-8 encoding is not supported"); diff --git a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java index 08c36d9281..64e71fa08a 100644 --- a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java +++ b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java @@ -34,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.web.multipart.MultipartFile; +import javax.annotation.Resource; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; @@ -42,8 +43,6 @@ import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; -import javax.annotation.Resource; - @Service @Transactional(rollbackFor = Exception.class) public class PerformanceTestService { @@ -381,6 +380,10 @@ public class PerformanceTestService { if (!CollectionUtils.isEmpty(loadTestFiles)) { loadTestFiles.forEach(loadTestFile -> { FileMetadata fileMetadata = fileService.copyFile(loadTestFile.getFileId()); + if (fileMetadata == null) { + // 如果性能测试出现文件变更,这里会有 null + return; + } loadTestFile.setTestId(copy.getId()); loadTestFile.setFileId(fileMetadata.getId()); loadTestFileMapper.insert(loadTestFile); diff --git a/backend/src/main/java/io/metersphere/service/FileService.java b/backend/src/main/java/io/metersphere/service/FileService.java index 952288f5f8..b82c2f784d 100644 --- a/backend/src/main/java/io/metersphere/service/FileService.java +++ b/backend/src/main/java/io/metersphere/service/FileService.java @@ -60,6 +60,10 @@ public class FileService { FileContentExample example2 = new FileContentExample(); example2.createCriteria().andFileIdIn(ids); fileContentMapper.deleteByExample(example2); + + LoadTestFileExample example3 = new LoadTestFileExample(); + example3.createCriteria().andFileIdIn(ids); + loadTestFileMapper.deleteByExample(example3); } public FileMetadata saveFile(MultipartFile file) { diff --git a/backend/src/main/java/io/metersphere/track/service/IssuesService.java b/backend/src/main/java/io/metersphere/track/service/IssuesService.java index 718fdcd05a..76e55cf953 100644 --- a/backend/src/main/java/io/metersphere/track/service/IssuesService.java +++ b/backend/src/main/java/io/metersphere/track/service/IssuesService.java @@ -224,6 +224,10 @@ public class IssuesService { String account = object.getString("account"); String password = object.getString("password"); String url = object.getString("url"); + String issuetype = object.getString("issuetype"); + if (StringUtils.isBlank(issuetype)) { + MSException.throwException("Jira 问题类型为空"); + } String auth = EncryptUtils.base64Encoding(account + ":" + password); String testCaseId = issuesRequest.getTestCaseId(); @@ -252,8 +256,7 @@ public class IssuesService { " \"summary\":\"" + issuesRequest.getTitle() + "\",\n" + " \"description\": " + JSON.toJSONString(desc) + ",\n" + " \"issuetype\":{\n" + - " \"id\":\"10009\",\n" + - " \"name\":\"Defect\"\n" + + " \"name\":\"" + issuetype + "\"\n" + " }\n" + " }\n" + "}"; diff --git a/backend/src/main/java/org/apache/jmeter/util/JSR223BeanInfoSupport.java b/backend/src/main/java/org/apache/jmeter/util/JSR223BeanInfoSupport.java new file mode 100644 index 0000000000..67568d3d13 --- /dev/null +++ b/backend/src/main/java/org/apache/jmeter/util/JSR223BeanInfoSupport.java @@ -0,0 +1,93 @@ +/* + * 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.util; + +import org.apache.jmeter.testbeans.TestBean; + +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; +import java.util.*; +import java.util.Map.Entry; + +/** + * 解决JSR233加载 ScriptEngineFactory 空指针问题 + */ +public abstract class JSR223BeanInfoSupport extends ScriptingBeanInfoSupport { + + private static final String[] LANGUAGE_TAGS; + + /** + * Will be removed in next version following 3.2 + * @deprecated use {@link JSR223BeanInfoSupport#getLanguageNames()} + */ + @Deprecated + public static final String[][] LANGUAGE_NAMES; // NOSONAR Kept for backward compatibility + + private static final String[][] CONSTANT_LANGUAGE_NAMES; + + static { + Map nameMap = new HashMap<>(); + ScriptEngineManager sem = new ScriptEngineManager(); + final List engineFactories = sem.getEngineFactories(); + for(ScriptEngineFactory fact : engineFactories){ + List names = fact.getNames(); + for(String shortName : names) { + if (shortName != null) { + nameMap.put(shortName.toLowerCase(Locale.ENGLISH), fact); + } + } + } + LANGUAGE_TAGS = nameMap.keySet().toArray(new String[nameMap.size()]); + Arrays.sort(LANGUAGE_TAGS); + CONSTANT_LANGUAGE_NAMES = new String[nameMap.size()][2]; + int i = 0; + for(Entry me : nameMap.entrySet()) { + final String key = me.getKey(); + CONSTANT_LANGUAGE_NAMES[i][0] = key; + final ScriptEngineFactory fact = me.getValue(); + CONSTANT_LANGUAGE_NAMES[i++][1] = key + + " (" // $NON-NLS-1$ + + fact.getLanguageName() + " " + fact.getLanguageVersion() // $NON-NLS-1$ + + " / " // $NON-NLS-1$ + + fact.getEngineName() + " " + fact.getEngineVersion() // $NON-NLS-1$ + + ")"; // $NON-NLS-1$ + } + + LANGUAGE_NAMES = getLanguageNames(); // NOSONAR Kept for backward compatibility + } + + private static final ResourceBundle NAME_BUNDLE = new ListResourceBundle() { + @Override + protected Object[][] getContents() { + return CONSTANT_LANGUAGE_NAMES; + } + }; + + protected JSR223BeanInfoSupport(Class beanClass) { + super(beanClass, LANGUAGE_TAGS, NAME_BUNDLE); + } + + /** + * @return String array of 2 columns array containing Script engine short name / Script Language details + */ + public static final String[][] getLanguageNames() { + return CONSTANT_LANGUAGE_NAMES.clone(); + } + +} diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 319222417c..e94db0ae4d 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -78,3 +78,4 @@ spring.servlet.multipart.max-request-size=500MB management.server.port=8083 management.endpoints.web.exposure.include=* +spring.freemarker.checkTemplateLocation=false diff --git a/backend/src/main/resources/db/migration/V17__test_plan_project.sql b/backend/src/main/resources/db/migration/V17__test_plan_project.sql new file mode 100644 index 0000000000..c1f57b0667 --- /dev/null +++ b/backend/src/main/resources/db/migration/V17__test_plan_project.sql @@ -0,0 +1,9 @@ +create table if not exists test_plan_project +( + test_plan_id varchar(50) null, + project_id varchar(50) null, + constraint test_plan_project_pk + unique (test_plan_id, project_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +insert into test_plan_project(test_plan_id, project_id) select id test_plan_id, project_id project_id from test_plan; \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V18__notice.sql b/backend/src/main/resources/db/migration/V18__notice.sql new file mode 100644 index 0000000000..2d6da6b5d7 --- /dev/null +++ b/backend/src/main/resources/db/migration/V18__notice.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS `notice`( + `EVENT` VARCHAR(100) NOT NULL, + `TEST_ID` VARCHAR(100) NOT NULL, + `NAME` VARCHAR(100) NOT NULL, + `EMAIL` VARCHAR(100) NOT NULL, + `ENABLE` VARCHAR(40) NOT NULL +)ENGINE=InnoDB DEFAULT CHARSET=utf8; + diff --git a/backend/src/main/resources/db/migration/V19__add_api_test_environment.sql b/backend/src/main/resources/db/migration/V19__add_api_test_environment.sql new file mode 100644 index 0000000000..d21de3e4e7 --- /dev/null +++ b/backend/src/main/resources/db/migration/V19__add_api_test_environment.sql @@ -0,0 +1 @@ +ALTER TABLE `api_test_environment` ADD `hosts` longtext COMMENT 'hosts '; \ No newline at end of file diff --git a/backend/src/main/resources/generatorConfig.xml b/backend/src/main/resources/generatorConfig.xml index 55775a43d5..df4684a270 100644 --- a/backend/src/main/resources/generatorConfig.xml +++ b/backend/src/main/resources/generatorConfig.xml @@ -65,6 +65,7 @@ +
diff --git a/docker/jmeter-master/run-test.sh b/docker/jmeter-master/run-test.sh index 54c94d91a9..98b1a02e7e 100644 --- a/docker/jmeter-master/run-test.sh +++ b/docker/jmeter-master/run-test.sh @@ -1,4 +1,3 @@ -export HEAP=$(cat /proc/meminfo | grep MemTotal | awk '{ mem=int($2/1024/1024 * 3/4 + 0.5); metasize=int(mem/4+0.5)"g"; if(mem<1) mem=1; if (metasize == "0g") metasize="256m"; HEAP="-Xms"mem"g -Xmx"mem"g -XX:MaxMetaspaceSize="metasize; print HEAP }') for file in ${TESTS_DIR}/*.jmx; do jmeter -n -t ${file} -Jserver.rmi.ssl.disable=${SSL_DISABLED} done diff --git a/frontend/src/assets/logo-dark-MeterSphere.svg b/frontend/src/assets/logo-dark-MeterSphere.svg index d0435794b8..1acbb1c0eb 100755 --- a/frontend/src/assets/logo-dark-MeterSphere.svg +++ b/frontend/src/assets/logo-dark-MeterSphere.svg @@ -1,85 +1,85 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/logo-light-MeterSphere.svg b/frontend/src/assets/logo-light-MeterSphere.svg index 23f11b796a..1fb78563d5 100755 --- a/frontend/src/assets/logo-light-MeterSphere.svg +++ b/frontend/src/assets/logo-light-MeterSphere.svg @@ -1,80 +1,80 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/business/components/api/head/ApiHeaderMenus.vue b/frontend/src/business/components/api/head/ApiHeaderMenus.vue index f1f461f5ad..9748c38f50 100644 --- a/frontend/src/business/components/api/head/ApiHeaderMenus.vue +++ b/frontend/src/business/components/api/head/ApiHeaderMenus.vue @@ -87,13 +87,17 @@ export default { } } }, + methods: { + registerEvents() { + ApiEvent.$on(LIST_CHANGE, () => { + this.$refs.projectRecent.recent(); + this.$refs.testRecent.recent(); + this.$refs.reportRecent.recent(); + }); + } + }, mounted() { - let self = this; - ApiEvent.$on(LIST_CHANGE, () => { - self.$refs.projectRecent.recent(); - self.$refs.testRecent.recent(); - self.$refs.reportRecent.recent(); - }); + this.registerEvents(); } } diff --git a/frontend/src/business/components/api/report/ApiReportView.vue b/frontend/src/business/components/api/report/ApiReportView.vue index 946200126d..9827f371b9 100644 --- a/frontend/src/business/components/api/report/ApiReportView.vue +++ b/frontend/src/business/components/api/report/ApiReportView.vue @@ -171,7 +171,7 @@ export default { diff --git a/frontend/src/business/components/api/test/components/ApiKeyValue.vue b/frontend/src/business/components/api/test/components/ApiKeyValue.vue index 4d13eac53f..ab0079d23e 100644 --- a/frontend/src/business/components/api/test/components/ApiKeyValue.vue +++ b/frontend/src/business/components/api/test/components/ApiKeyValue.vue @@ -5,6 +5,11 @@
+ + + + diff --git a/frontend/src/business/components/api/test/components/ApiScenarioConfig.vue b/frontend/src/business/components/api/test/components/ApiScenarioConfig.vue index 3750d18013..ba91dce801 100644 --- a/frontend/src/business/components/api/test/components/ApiScenarioConfig.vue +++ b/frontend/src/business/components/api/test/components/ApiScenarioConfig.vue @@ -207,7 +207,12 @@ export default { }); this.scenarios.forEach(scenario => { if (scenario.environmentId) { - scenario.environment = environmentMap.get(scenario.environmentId); + let env = environmentMap.get(scenario.environmentId); + if (!env) { + scenario.environmentId = undefined; + } else { + scenario.environment = env; + } } }); }); diff --git a/frontend/src/business/components/api/test/components/ApiVariable.vue b/frontend/src/business/components/api/test/components/ApiVariable.vue index aa9a29da1e..daa4f1956a 100644 --- a/frontend/src/business/components/api/test/components/ApiVariable.vue +++ b/frontend/src/business/components/api/test/components/ApiVariable.vue @@ -5,12 +5,18 @@
+ + + + - + @@ -31,12 +37,12 @@ value-key="name" highlight-first-item @select="change"> - + - + diff --git a/frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue b/frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue index 0f21c11a20..684d38ea9e 100644 --- a/frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue +++ b/frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue @@ -1,13 +1,12 @@ diff --git a/frontend/src/business/components/api/test/components/request/ApiDubboRequestForm.vue b/frontend/src/business/components/api/test/components/request/ApiDubboRequestForm.vue index 8746a80bb4..9cc19b2f99 100644 --- a/frontend/src/business/components/api/test/components/request/ApiDubboRequestForm.vue +++ b/frontend/src/business/components/api/test/components/request/ApiDubboRequestForm.vue @@ -45,10 +45,10 @@ - + - + @@ -65,12 +65,12 @@ import MsDubboRegistryCenter from "@/business/components/api/test/components/request/dubbo/RegistryCenter"; import MsDubboConfigCenter from "@/business/components/api/test/components/request/dubbo/ConfigCenter"; import MsDubboConsumerService from "@/business/components/api/test/components/request/dubbo/ConsumerAndService"; - import MsBeanShellProcessor from "../processor/BeanShellProcessor"; + import MsJsr233Processor from "../processor/Jsr233Processor"; export default { name: "MsApiDubboRequestForm", components: { - MsBeanShellProcessor, + MsJsr233Processor, MsDubboConsumerService, MsDubboConfigCenter, MsDubboRegistryCenter, diff --git a/frontend/src/business/components/api/test/components/request/ApiHttpRequestForm.vue b/frontend/src/business/components/api/test/components/request/ApiHttpRequestForm.vue index 73ce12e6e8..c9a8353c5c 100644 --- a/frontend/src/business/components/api/test/components/request/ApiHttpRequestForm.vue +++ b/frontend/src/business/components/api/test/components/request/ApiHttpRequestForm.vue @@ -38,6 +38,7 @@ v-model="request.useEnvironment" :active-text="$t('api_test.request.refer_to_environment')" @change="useEnvironmentChange"> + - + - - + + - - + + @@ -92,16 +92,15 @@ import MsApiExtract from "../extract/ApiExtract"; import ApiRequestMethodSelect from "../collapse/ApiRequestMethodSelect"; import {REQUEST_HEADERS} from "@/common/js/constants"; import MsApiVariable from "@/business/components/api/test/components/ApiVariable"; -import MsBeanShellProcessor from "../processor/BeanShellProcessor"; +import MsJsr233Processor from "../processor/Jsr233Processor"; import MsApiAdvancedConfig from "../ApiAdvancedConfig"; export default { name: "MsApiHttpRequestForm", components: { + MsJsr233Processor, MsApiAdvancedConfig, - MsBeanShellProcessor, - MsApiVariable, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiBody, MsApiKeyValue - }, + MsApiVariable, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiBody, MsApiKeyValue}, props: { request: HttpRequest, scenario: Scenario, @@ -225,4 +224,8 @@ export default { color: #F56C6C; } +.follow-redirects-item { + margin-left: 30px; +} + diff --git a/frontend/src/business/components/api/test/components/request/ApiRequestForm.vue b/frontend/src/business/components/api/test/components/request/ApiRequestForm.vue index 43efd82cf2..486021ee66 100644 --- a/frontend/src/business/components/api/test/components/request/ApiRequestForm.vue +++ b/frontend/src/business/components/api/test/components/request/ApiRequestForm.vue @@ -8,7 +8,7 @@ diff --git a/frontend/src/business/components/common/components/MsScheduleEdit.vue b/frontend/src/business/components/common/components/MsScheduleEdit.vue index 853cf166c9..b7b0f1d542 100644 --- a/frontend/src/business/components/common/components/MsScheduleEdit.vue +++ b/frontend/src/business/components/common/components/MsScheduleEdit.vue @@ -1,5 +1,5 @@