us.abstracta.jmeter.javadsl.http.DslBaseHttpSampler Maven / Gradle / Ivy
Show all versions of jmeter-java-dsl Show documentation
package us.abstracta.jmeter.javadsl.http;
import static us.abstracta.jmeter.javadsl.JmeterDsl.jsr223PreProcessor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.function.Function;
import org.apache.http.entity.ContentType;
import org.apache.jmeter.gui.JMeterGUIComponent;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.protocol.http.util.HTTPConstants;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import us.abstracta.jmeter.javadsl.JmeterDsl;
import us.abstracta.jmeter.javadsl.codegeneration.MethodCall;
import us.abstracta.jmeter.javadsl.codegeneration.MethodCallContext;
import us.abstracta.jmeter.javadsl.codegeneration.MethodParam.IntParam;
import us.abstracta.jmeter.javadsl.codegeneration.MethodParam.StringParam;
import us.abstracta.jmeter.javadsl.codegeneration.SingleGuiClassCallBuilder;
import us.abstracta.jmeter.javadsl.codegeneration.TestElementParamBuilder;
import us.abstracta.jmeter.javadsl.core.BuildTreeContext;
import us.abstracta.jmeter.javadsl.core.preprocessors.DslJsr223PreProcessor.PreProcessorScript;
import us.abstracta.jmeter.javadsl.core.preprocessors.DslJsr223PreProcessor.PreProcessorVars;
import us.abstracta.jmeter.javadsl.core.samplers.BaseSampler;
/**
* Abstracts common logic used by HTTP based samplers.
*
* @param type of the sampler used to provide proper fluent API methods.
* @since 0.52
*/
public abstract class DslBaseHttpSampler> extends BaseSampler {
protected String path;
protected final HttpHeaders headers = new HttpHeaders();
private String protocol;
private String host;
private String port;
public DslBaseHttpSampler(String name, String url, Class guiClass) {
super(name, guiClass);
if (url == null) {
return;
}
JmeterUrl parsedUrl = JmeterUrl.valueOf(url);
protocol = parsedUrl.protocol();
host = parsedUrl.host();
port = parsedUrl.port();
path = parsedUrl.path();
}
/**
* Specifies the HTTP Sampler protocol to be used in the HTTP request generated by the sampler.
*
* You can specify entire url when creating a sampler, but this method allows you to override the
* protocol if needed. For example, if you have defaults element with url and just need in one
* sampler to have a different protocol.
*
* In general prefer using java variables and methods, to get shorter and more maintainable code,
* and use this method sparingly.
*
* @param protocol contains protocol value to be used (e.g.: http, https, etc).
* @return the altered sampler to allow for fluent API usage.
*/
public T protocol(String protocol) {
this.protocol = protocol;
return (T) this;
}
/**
* Specifies the server host (domain) to be used in the HTTP request generated by the sampler.
*
* You can specify entire url when creating a sampler, but this method allows you to override the
* host if needed. For example, if you have defaults element with url and just need in one sampler
* to have a different host.
*
* In general prefer using java variables and methods, to get shorter and more maintainable code,
* and use this method sparingly.
*
* @param host contains server name without protocol (no http/https) and path.
* @return the altered sampler to allow for fluent API usage.
*/
public T host(String host) {
this.host = host;
return (T) this;
}
/**
* Specifies the HTTP Sampler port to be used in the HTTP request generated by the sampler.
*
* You can specify entire url when creating a sampler, but this method allows you to override the
* port if needed. For example, if you have defaults element with url and just need in one sampler
* to have a different port.
*
* In general prefer using java variables and methods, to get shorter and more maintainable code,
* and use this method sparingly.
*
* @param port contains port value to be used.
* @return the altered sampler to allow for fluent API usage.
*/
public T port(int port) {
this.port = String.valueOf(port);
return (T) this;
}
/**
* Specifies an HTTP header to be sent by the sampler.
*
* To specify multiple headers just invoke this method several times with the different header
* names and values.
*
* @param name of the HTTP header.
* @param value of the HTTP header.
* @return the altered sampler to allow for fluent API usage.
*/
public T header(String name, String value) {
headers.header(name, value);
return (T) this;
}
/**
* Same as {@link #header(String, String)} but allows using dynamically calculated HTTP header
* value.
*
* This method is just an abstraction that uses a JMeter variable as HTTP header value and
* calculates the variable with a jsr223PreProcessor.
*
* WARNING: As this method internally uses
* {@link JmeterDsl#jsr223PreProcessor(PreProcessorScript)}, same limitations and considerations
* apply. Check its documentation. To avoid such limitations you may use {@link #header(String,
* String)} with a JMeter variable instead, and dynamically set the variable with {@link
* JmeterDsl#jsr223PreProcessor(String)}.
*
* @param name of the HTTP header.
* @param valueSupplier builds the header value.
* @return the altered sampler to allow for fluent API usage.
*/
public T header(String name, Function valueSupplier) {
String variableNamePrefix = "PRE_PROCESSOR_HEADER~";
headers.header(name, "${" + variableNamePrefix + name + "}");
return children(
jsr223PreProcessor(s -> s.vars.put(variableNamePrefix + name, valueSupplier.apply(s)))
);
}
/**
* Allows to easily specify the Content-Type HTTP header to be used by the sampler.
*
* @param contentType value to send as Content-Type header.
* @return the altered sampler to allow for fluent API usage.
*/
public T contentType(ContentType contentType) {
headers.contentType(contentType);
return (T) this;
}
@Override
protected TestElement buildTestElement() {
HTTPSamplerProxy ret = new HTTPSamplerProxy();
if (protocol != null) {
ret.setProtocol(protocol);
}
if (host != null) {
ret.setDomain(host);
}
if (port != null) {
/*
need to use this method instead of setPort since we want to be able to set expressions on
port (like ${port}).
*/
ret.setProperty(HTTPSamplerBase.PORT, port);
}
if (path != null) {
ret.setPath(path);
}
return configureHttpTestElement(ret);
}
protected abstract HTTPSamplerProxy configureHttpTestElement(HTTPSamplerProxy elem);
@Override
public HashTree buildTreeUnder(HashTree parent, BuildTreeContext context) {
HashTree ret = super.buildTreeUnder(parent, context);
if (!headers.isEmpty()) {
context.buildChild(headers, ret);
}
new DslCookieManager().registerDependency(context);
new DslCacheManager().registerDependency(context);
return ret;
}
protected abstract static class BaseHttpSamplerCodeBuilder extends SingleGuiClassCallBuilder {
private final String defaultName;
protected BaseHttpSamplerCodeBuilder(String defaultName,
Class guiClass, List builderMethods) {
super(guiClass, builderMethods);
this.defaultName = defaultName;
}
@Override
protected MethodCall buildMethodCall(MethodCallContext context) {
HTTPSamplerProxy testElement = (HTTPSamplerProxy) context.getTestElement();
TestElementParamBuilder paramBuilder = new TestElementParamBuilder(testElement);
StringParam name = paramBuilder.nameParam(defaultName);
StringParam protocol = paramBuilder.stringParam(HTTPSamplerBase.PROTOCOL);
StringParam domain = paramBuilder.stringParam(HTTPSamplerBase.DOMAIN);
IntParam port = paramBuilder.intParam(HTTPSamplerBase.PORT);
StringParam path = paramBuilder.stringParam(HTTPSamplerBase.PATH, "/");
StringParam url = buildUrlParam(protocol, domain, port, path);
MethodCall ret = buildBaseHttpMethodCall(name, url, paramBuilder);
context.findBuilder(DslCacheManager.CodeBuilder.class)
.registerDependency(context, ret);
context.findBuilder(DslCookieManager.CodeBuilder.class)
.registerDependency(context, ret);
if (url == path) {
ret.chain("protocol", protocol)
.chain("host", domain)
.chain("port", port);
}
buildRequestCall(ret, testElement, context);
setAdditionalOptions(ret, paramBuilder);
return ret;
}
protected abstract MethodCall buildBaseHttpMethodCall(StringParam name, StringParam url,
TestElementParamBuilder paramBuilder);
private StringParam buildUrlParam(StringParam protocol, StringParam domain, IntParam port,
StringParam path) {
if (!domain.isDefault()) {
return new StringParam(
(protocol.isDefault() ? "http" : protocol.getValue()) + "://"
+ domain.getValue()
+ (port.isDefault() ? "" : ":" + port.getValue())
+ (path.isDefault() ? "" : path.getValue()));
} else {
return path;
}
}
protected abstract void buildRequestCall(MethodCall ret, HTTPSamplerProxy testElement,
MethodCallContext context);
protected String removeContentTypeHeader(MethodCallContext context) {
if (context == null) {
return null;
}
String headerName = HTTPConstants.HEADER_CONTENT_TYPE;
HeaderManager headers = (HeaderManager) context.getTestElement();
Header header = headers.getFirstHeaderNamed(headerName);
headers.removeHeaderNamed(headerName);
return header == null ? null : header.getValue();
}
protected void chainContentType(MethodCall ret, String contentType) {
ret.chain("contentType", new ContentTypeParam(contentType));
}
protected void chainHeaders(MethodCall ret, MethodCallContext headers) {
if (headers != null) {
ret.reChain(headers.buildMethodCall());
}
}
protected abstract void setAdditionalOptions(MethodCall ret,
TestElementParamBuilder paramBuilder);
}
}