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/backend/pom.xml b/backend/pom.xml index ab5270911f..228700a300 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -153,6 +153,12 @@ + + org.python + jython + 2.7.2 + + org.apache.jmeter ApacheJMeter_functions 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 33bdc7c3be..48c7676286 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; @@ -51,4 +53,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 ca7855311a..fed20e7a21 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; @@ -48,5 +50,9 @@ public class HttpRequest implements Request { @JSONField(ordinal = 15) private Long responseTimeout; @JSONField(ordinal = 16) - private Boolean followRedirects;; + 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/org/apache/jmeter/util/JSR223BeanInfoSupport.java b/backend/src/main/java/org/apache/jmeter/util/JSR223BeanInfoSupport.java new file mode 100644 index 0000000000..38fd39589c --- /dev/null +++ b/backend/src/main/java/org/apache/jmeter/util/JSR223BeanInfoSupport.java @@ -0,0 +1,100 @@ +/* + * 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 java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.ListResourceBundle; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.ResourceBundle; + +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; + +import org.apache.jmeter.testbeans.TestBean; + +/** + * 解决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 extends TestBean> 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/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/test/components/ApiScenarioConfig.vue b/frontend/src/business/components/api/test/components/ApiScenarioConfig.vue index ce88447354..62b6479b99 100644 --- a/frontend/src/business/components/api/test/components/ApiScenarioConfig.vue +++ b/frontend/src/business/components/api/test/components/ApiScenarioConfig.vue @@ -166,7 +166,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/processor/BeanShellProcessor.vue b/frontend/src/business/components/api/test/components/processor/Jsr233Processor.vue similarity index 74% rename from frontend/src/business/components/api/test/components/processor/BeanShellProcessor.vue rename to frontend/src/business/components/api/test/components/processor/Jsr233Processor.vue index 38f39566fc..9d449ab8b1 100644 --- a/frontend/src/business/components/api/test/components/processor/BeanShellProcessor.vue +++ b/frontend/src/business/components/api/test/components/processor/Jsr233Processor.vue @@ -2,9 +2,10 @@ - + + {{$t('api_test.request.processor.code_template')}} {{template.title}} @@ -21,9 +22,13 @@