build: 动态解析插件数据

This commit is contained in:
fit2-zhao 2023-06-07 14:06:11 +08:00 committed by 刘瑞斌
parent 931c7c7e1b
commit 4610d0919e
6 changed files with 241 additions and 6 deletions

View File

@ -0,0 +1,12 @@
package io.metersphere.plugin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PluginSubType {
String value();
}

View File

@ -4,25 +4,22 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.metersphere.plugin.util.PluginLogUtils; import io.metersphere.plugin.util.PluginLogUtils;
import lombok.Data; import lombok.Data;
import org.apache.jmeter.save.SaveService; import org.apache.jmeter.save.SaveService;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree; import org.apache.jorphan.collections.ListedHashTree;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "clazzName")
@Data @Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public abstract class TestElementDTO { public abstract class TestElementDTO implements Serializable {
// 组件类型 // 组件类型
private String type; private String type;
// 用于数据反射对象
private String clazzName = TestElementDTO.class.getCanonicalName();
// 当前组件唯一标示 // 当前组件唯一标示
private String uuid; private String uuid;

View File

@ -0,0 +1,26 @@
package io.metersphere.api.dto.jmeter.processors;
import io.metersphere.plugin.annotation.PluginSubType;
import io.metersphere.plugin.api.dto.BaseConfigDTO;
import io.metersphere.plugin.api.dto.TestElementDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@PluginSubType("MSJSR223Processor")
public class MSJSR223Processor extends TestElementDTO {
private String script;
private String scriptLanguage;
private Boolean jsrEnable;
@Override
public void toHashTree(HashTree tree, List<TestElementDTO> hashTree, BaseConfigDTO baseConfig) {
if (!this.isEnable()) {
return;
}
}
}

View File

@ -0,0 +1,64 @@
package io.metersphere.api.dto.jmeter.sampler;
import io.metersphere.plugin.annotation.PluginSubType;
import io.metersphere.plugin.api.dto.BaseConfigDTO;
import io.metersphere.plugin.api.dto.TestElementDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.sampler.DebugSampler;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@PluginSubType("MSDebugSampler")
public class MSDebugSampler extends TestElementDTO {
private boolean displayJMeterProperties = false;
private boolean displayJMeterVariables = true;
private boolean displaySystemProperties = false;
@Override
public void toHashTree(HashTree tree, List<TestElementDTO> hashTree, BaseConfigDTO configDTO) {
BaseConfigDTO config = (BaseConfigDTO) configDTO;
// 非导出操作且不是启用状态则跳过执行
if (!this.isEnable()) {
return;
}
final HashTree groupTree = tree.add(debugSampler());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
// 给所有孩子加一个父亲标志
el.setParent(this);
el.toHashTree(groupTree, el.getHashTree(), config);
});
}
}
private DebugSampler debugSampler() {
DebugSampler debugSampler = new DebugSampler();
debugSampler.setEnabled(this.isEnable());
if (StringUtils.isEmpty(this.getName())) {
this.setName(MSDebugSampler.class.getSimpleName());
}
debugSampler.setName(this.getName());
debugSampler.setProperty(TestElement.TEST_CLASS, DebugSampler.class.getName());
debugSampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
debugSampler.setDisplaySystemProperties(this.displaySystemProperties);
debugSampler.setDisplayJMeterVariables(this.displayJMeterVariables);
debugSampler.setDisplayJMeterProperties(this.displayJMeterProperties);
//上面三行直接Set属性会导致DebugSampler构建时取不到值可能是JMeter的Bug,需要SetProperty
debugSampler.setProperty("displayJMeterProperties", this.displayJMeterProperties);
debugSampler.setProperty("displayJMeterVariables", this.displayJMeterVariables);
debugSampler.setProperty("displaySystemProperties", this.displaySystemProperties);
return debugSampler;
}
}

View File

@ -0,0 +1,98 @@
package io.metersphere.api.util;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.jsontype.impl.StdSubtypeResolver;
import com.fasterxml.jackson.databind.type.CollectionType;
import io.metersphere.api.dto.jmeter.processors.MSJSR223Processor;
import io.metersphere.api.dto.jmeter.sampler.MSDebugSampler;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
public class JSONUtils {
private static final ObjectMapper objectMapper = new ObjectMapper();
private static StdSubtypeResolver resolver = new StdSubtypeResolver();
static {
// 添加处理资源文件的类
final List<NamedType> namedTypes = new LinkedList<>();
namedTypes.add(new NamedType(MSJSR223Processor.class, MSJSR223Processor.class.getSimpleName()));
namedTypes.add(new NamedType(MSDebugSampler.class, MSDebugSampler.class.getSimpleName()));
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 自动检测所有类的全部属性
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
// 如果一个对象中没有任何的属性那么在序列化的时候就会报错
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
namedTypes.forEach(namedType -> resolver.registerSubtypes(namedType));
objectMapper.setSubtypeResolver(resolver);
}
public static String toJSONString(Object value) {
try {
return objectMapper.writeValueAsString(value);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static Object parseObject(String content) {
return parseObject(content, Object.class);
}
public static <T> T parseObject(String content, Class<T> valueType) {
try {
return objectMapper.readValue(content, valueType);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static <T> T parseObject(InputStream src, Class<T> valueType) {
try {
return objectMapper.readValue(src, valueType);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static <T> T parseObject(String content, TypeReference<T> valueType) {
try {
return objectMapper.readValue(content, valueType);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static List parseArray(String content) {
return parseArray(content, Object.class);
}
public static <T> List<T> parseArray(String content, Class<T> valueType) {
CollectionType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, valueType);
try {
return objectMapper.readValue(content, javaType);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 设置动态加载的jar的Resolver
*
* @param namedTypes
*/
public static void setResolver(List<NamedType> namedTypes) {
namedTypes.forEach(namedType -> resolver.registerSubtypes(namedType));
objectMapper.setSubtypeResolver(resolver);
}
}

View File

@ -0,0 +1,38 @@
package io.metersphere.api.controller;
import io.metersphere.api.dto.jmeter.processors.MSJSR223Processor;
import io.metersphere.api.dto.jmeter.sampler.MSDebugSampler;
import io.metersphere.api.util.JSONUtils;
import io.metersphere.plugin.api.dto.TestElementDTO;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.LinkedList;
import java.util.UUID;
@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@AutoConfigureMockMvc
public class PluginSubTypeTests {
@Test
@Order(0)
public void pluginSubTypeTest() throws Exception {
MSDebugSampler debugSampler = new MSDebugSampler();
debugSampler.setName("测试DebugSampler");
debugSampler.setUuid(UUID.randomUUID().toString());
LinkedList<TestElementDTO> hashTree = new LinkedList<>();
hashTree.add(debugSampler);
MSJSR223Processor msjsr223Processor = new MSJSR223Processor();
msjsr223Processor.setName("测试jsr223");
msjsr223Processor.setJsrEnable(true);
msjsr223Processor.setHashTree(hashTree);
String json = JSONUtils.toJSONString(msjsr223Processor);
Assertions.assertNotNull(json);
TestElementDTO testElementDTO = JSONUtils.parseObject(json, TestElementDTO.class);
Assertions.assertNotNull(testElementDTO);
}
}