All Downloads are FREE. Search and download functionalities are using the official Maven repository.

us.abstracta.jmeter.javadsl.codegeneration.MethodParam Maven / Gradle / Ivy

Go to download

Simple API to run JMeter performance tests in an VCS and programmers friendly way.

There is a newer version: 028
Show newest version
package us.abstracta.jmeter.javadsl.codegeneration;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import us.abstracta.jmeter.javadsl.core.assertions.DslAssertion;
import us.abstracta.jmeter.javadsl.core.configs.DslConfig;
import us.abstracta.jmeter.javadsl.core.configs.DslVariables;
import us.abstracta.jmeter.javadsl.core.controllers.DslController;
import us.abstracta.jmeter.javadsl.core.listeners.DslListener;
import us.abstracta.jmeter.javadsl.core.postprocessors.DslPostProcessor;
import us.abstracta.jmeter.javadsl.core.preprocessors.DslPreProcessor;
import us.abstracta.jmeter.javadsl.core.samplers.DslSampler;
import us.abstracta.jmeter.javadsl.core.threadgroups.DslThreadGroup;
import us.abstracta.jmeter.javadsl.core.timers.DslTimer;

/**
 * Generates code for a MethodCall parameter.
 * 

* This class should be extended to implement custom types of parameters (eg: check {@link * us.abstracta.jmeter.javadsl.http.ContentTypeParam} * * @param Is the type of the parameter value. * @since 0.45 */ public abstract class MethodParam { protected final T value; protected final T defaultValue; protected final Class paramType; protected MethodParam(Class paramType, T value, T defaultValue) { this.paramType = paramType; this.value = value; this.defaultValue = defaultValue; } protected Class getType() { return this.paramType; } /** * Gets the value associated to the parameter. * * @return the value. */ public T getValue() { return value; } /** * Allows checking if a parameter is set to the default value. *

* This is usually used in {@link MethodCallBuilder} instances to check if a parameter is set or * not to some custom value, and some method chaingin is required or not. *

* This method may, and is, overwritten by subclasses depending on the semantics of each type of * parameter. * * @return true when the value is the default one or not specified (null), false otherwise. */ public boolean isDefault() { return defaultValue != null && defaultValue.equals(value) || value == null; } protected boolean isIgnored() { return false; } protected abstract String buildCode(String indent); protected static Map findConstantNames(Class constantsHolderClass, Class constantClass, Predicate filter) { return Arrays.stream(constantsHolderClass.getDeclaredFields()) .filter(f -> Modifier.isPublic(f.getModifiers()) && Modifier.isStatic(f.getModifiers()) && Modifier.isFinal(f.getModifiers()) && f.getType() == constantClass && filter.test(f)) .collect(Collectors.toMap(f -> { try { return constantClass.cast(f.get(null)); } catch (IllegalAccessException e) { // this should never happen since we are iterating over public static fields throw new RuntimeException(e); } }, Field::getName)); } /** * Is a parameter associated to a test element name. *

* This type of parameter has the special consideration that when names are set to default values, * then they can be ignored. */ public static class NameParam extends StringParam { public NameParam(String name, String defaultName) { super(name, defaultName); } @Override public boolean isIgnored() { return isDefault(); } } /** * Is a parameter with a string value. *

* This implementation in particular takes care of proper escaping of characters for code * generation. */ public static class StringParam extends MethodParam { public StringParam(String value, String defaultValue) { super(String.class, value, defaultValue); } public StringParam(String value) { this(value, null); } @Override public boolean isDefault() { return super.isDefault() || value.isEmpty(); } @Override public String buildCode(String indent) { return "\"" + value.replaceAll("[\\\\\"\n\t\r]", "\\\\$0") + "\""; } } /** * This represents parameters for which generated code does not need any sort of transformation on * the assigned value. * * @param The type of the parameter value. */ public abstract static class LiteralParam extends MethodParam { protected LiteralParam(Class paramType, T value, T defaultValue) { super(paramType, value, defaultValue); } @Override public String buildCode(String indent) { return String.valueOf(value); } } /** * Is a parameter with an integer value. */ public static class IntParam extends LiteralParam { public IntParam(Integer value, Integer defaultValue) { super(int.class, value, defaultValue); } public IntParam(Integer value) { this(value, null); } } /** * Is a parameter with an integer value. */ public static class LongParam extends LiteralParam { public LongParam(Long value, Long defaultValue) { super(long.class, value, defaultValue); } public LongParam(Long value) { this(value, null); } } /** * Is a parameter with a boolean (true/false) value. */ public static class BoolParam extends LiteralParam { public BoolParam(Boolean value, Boolean defaultValue) { super(boolean.class, value == null ? Boolean.FALSE : value, defaultValue); } } /** * Is a parameter with a Duration value. */ public static class DurationParam extends MethodParam { public DurationParam(Duration value, Duration defaultValue) { super(Duration.class, value, defaultValue); } public DurationParam(Duration value) { this(value, null); } @Override public String buildCode(String indent) { return value.isZero() ? Duration.class.getSimpleName() + ".ZERO" : MethodCall.forStaticMethod(Duration.class, "ofSeconds", new LongParam(value.getSeconds())).buildCode(); } } /** * Is a parameter used to specify DSL test element children methods. *

* This is usually used in TestElementContainer instances which usually provide a builder method * with basic required parameters and children elements (eg: thread groups & controllers). * * @param The type of the children DSl test elements. */ public static class ChildrenParam extends MethodParam { private static final Class[][] EXECUTION_ORDERS = new Class[][]{ {DslVariables.class}, {DslConfig.class}, {DslPreProcessor.class}, {DslTimer.class}, {DslThreadGroup.class, DslController.class, DslSampler.class}, {DslPostProcessor.class}, {DslAssertion.class}, {DslListener.class} }; private final List children = new ArrayList<>(); public ChildrenParam(Class childrenClass) { super(checkChildrenType(childrenClass), null, null); } private static Class checkChildrenType(Class childrenClass) { if (!childrenClass.isArray()) { throw new IllegalArgumentException( "You need always to provide an array class and not the raw class for the children. " + "Eg use TestPlanChild[].class"); } return childrenClass; } @Override public String buildCode(String indent) { List childrenCalls = children.stream() // order elements to provide the most intuitive representation and ease tests .sorted(Comparator.comparing(c -> findExecutionOrder(c.getReturnType()))) .collect(Collectors.toList()); String ret = childrenCalls.stream() .map(c -> c.buildCode(indent)) .filter(s -> !s.isEmpty()) .collect(Collectors.joining(",\n" + indent)); return ret.isEmpty() ? ret : "\n" + indent + ret + "\n"; } private static int findExecutionOrder(Class returnType) { for (int i = 0; i < EXECUTION_ORDERS.length; i++) { if (Arrays.stream(EXECUTION_ORDERS[i]) .anyMatch(c -> c.isAssignableFrom(returnType))) { return i; } } return -1; } public void addChild(MethodCall child) { Class childrenType = paramType.getComponentType(); if (!childrenType.isAssignableFrom(child.getReturnType())) { throw new IllegalArgumentException("Trying to add a child of type " + child.getReturnType() + " that is not compatible with the declared ones : " + childrenType); } children.add(child); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy