Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public ArgumentsSchema getSchema() {
* @return the arguments
*/
public CollectionProperty getArguments() {
return (CollectionProperty) getPropertyOrNull(getSchema().getArguments());
return getOrNull(getSchema().getArguments());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -488,38 +488,37 @@ public interface TestElement : Cloneable {
}

/**
* Retrieve [Collection] property value, or throw [NoSuchElementException] in case the property is unset.
* Retrieve [CollectionProperty] property value, or throw [NoSuchElementException] in case the property is unset.
* @throws NoSuchElementException if the property is unset
* @since 5.6
*/
@JMeterPropertySchemaUnchecked
@API(status = API.Status.EXPERIMENTAL, since = "5.6")
public operator fun get(property: CollectionPropertyDescriptor<*>): Collection<JMeterProperty> =
public operator fun get(property: CollectionPropertyDescriptor<*>): CollectionProperty =
getOrNull(property) ?: throw NoSuchElementException("Property ${property.name} is unset for element $this")

/**
* Retrieve [Collection] property value, or return `null` in case the property is unset.
* Retrieve [CollectionProperty] property value, or return `null` in case the property is unset.
* @since 5.6
*/
@JMeterPropertySchemaUnchecked
@API(status = API.Status.EXPERIMENTAL, since = "5.6")
public fun getOrNull(property: CollectionPropertyDescriptor<*>): Collection<JMeterProperty>? =
public fun getOrNull(property: CollectionPropertyDescriptor<*>): CollectionProperty? =
getPropertyOrNull(property)?.let {
@Suppress("UNCHECKED_CAST")
(it as CollectionProperty).objectValue as Collection<JMeterProperty>
it as CollectionProperty
}

/**
* Retrieve [Collection] property value, or create one and set it the property is unset.
* Retrieve [CollectionProperty] property value, or create one and set it the property is unset.
* @since 5.6
*/
@JMeterPropertySchemaUnchecked
@API(status = API.Status.EXPERIMENTAL, since = "5.6")
public fun getOrCreate(
property: CollectionPropertyDescriptor<*>,
ifMissing: () -> Collection<JMeterProperty>
): Collection<JMeterProperty> =
getOrNull(property) ?: ifMissing().also { set(property, it) }
): CollectionProperty =
getOrNull(property) ?: CollectionProperty(property.name, ifMissing()).also { setProperty(it) }

/**
* Set property as [Collection], or remove it if the given [Collection] is `null`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,22 @@ public data class CollectionPropertyDescriptor<in Schema : BaseTestElementSchema
override val defaultValue: Collection<JMeterProperty>? = null

/**
* Retrieve [Collection] property value, or throw [NoSuchElementException] in case the property is unset.
* Retrieve [CollectionProperty] property value, or throw [NoSuchElementException] in case the property is unset.
* @throws NoSuchElementException if the property is unset
*/
public operator fun get(target: TestElement): Collection<JMeterProperty> =
public operator fun get(target: TestElement): CollectionProperty =
target[this]

/**
* Retrieve [Collection] property value, or return `null` in case the property is unset.
* Retrieve [CollectionProperty] property value, or return `null` in case the property is unset.
*/
public fun getOrNull(target: TestElement): Collection<JMeterProperty>? =
public fun getOrNull(target: TestElement): CollectionProperty? =
target.getOrNull(this)

/**
* Retrieve [Collection] property value, or create one and set it the property is unset.
* Retrieve [CollectionProperty] property value, or create one and set it the property is unset.
*/
public fun getOrCreate(target: TestElement, ifMissing: () -> Collection<JMeterProperty>): Collection<JMeterProperty> =
public fun getOrCreate(target: TestElement, ifMissing: () -> Collection<JMeterProperty>): CollectionProperty =
target.getOrCreate(this, ifMissing)

public operator fun set(target: TestElement, value: Collection<*>?) {
Expand All @@ -64,7 +64,7 @@ public data class CollectionPropertyDescriptor<in Schema : BaseTestElementSchema

@JvmSynthetic
@Suppress("NOTHING_TO_INLINE")
public inline operator fun getValue(testElement: TestElement, property: KProperty<*>): Collection<JMeterProperty> {
public inline operator fun getValue(testElement: TestElement, property: KProperty<*>): CollectionProperty {
return testElement[this]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.jmeter.testelement.schema

import org.apache.jmeter.testelement.TestElement
import org.apache.jmeter.testelement.property.CollectionProperty
import org.apache.jmeter.testelement.property.JMeterProperty
import org.apiguardian.api.API
import kotlin.experimental.ExperimentalTypeInference
Expand Down Expand Up @@ -136,14 +137,22 @@ public class PropertiesAccessor<out TestElementClass : TestElement, out Schema :
propertySelector(schema).getString(target)

// Class properties
public operator fun <ValueClass : Any> get(property: ClassPropertyDescriptor<Schema, ValueClass>): Class<out ValueClass>? =
public operator fun <ValueClass : Any> get(property: ClassPropertyDescriptor<Schema, ValueClass>): Class<out ValueClass> =
target[property]

public fun <ValueClass : Any> getOrNull(property: ClassPropertyDescriptor<Schema, ValueClass>): Class<out ValueClass>? =
target.getOrNull(property)

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public operator fun <ValueClass : Any> get(propertySelector: Schema.() -> ClassPropertyDescriptor<Schema, ValueClass>): Class<out ValueClass>? =
public operator fun <ValueClass : Any> get(propertySelector: Schema.() -> ClassPropertyDescriptor<Schema, ValueClass>): Class<out ValueClass> =
get(propertySelector(schema))

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public fun <ValueClass : Any> getOrNull(propertySelector: Schema.() -> ClassPropertyDescriptor<Schema, ValueClass>): Class<out ValueClass>? =
getOrNull(propertySelector(schema))

public operator fun <ValueClass : Any> set(
property: ClassPropertyDescriptor<Schema, ValueClass>,
value: KClass<out ValueClass>
Expand All @@ -153,21 +162,21 @@ public class PropertiesAccessor<out TestElementClass : TestElement, out Schema :

public inline operator fun <ValueClass : Any> set(
propertySelector: Schema.() -> ClassPropertyDescriptor<Schema, ValueClass>,
value: KClass<ValueClass>
value: KClass<ValueClass>?
) {
set(propertySelector, value.java)
set(propertySelector, value?.java)
}

public operator fun <ValueClass : Any> set(
property: ClassPropertyDescriptor<Schema, ValueClass>,
value: Class<out ValueClass>
value: Class<out ValueClass>?
) {
target[property] = value
}

public inline operator fun <ValueClass : Any> set(
propertySelector: Schema.() -> ClassPropertyDescriptor<Schema, ValueClass>,
value: Class<ValueClass>
value: Class<ValueClass>?
) {
target[propertySelector(schema)] = value
}
Expand Down Expand Up @@ -253,44 +262,60 @@ public class PropertiesAccessor<out TestElementClass : TestElement, out Schema :
}

// TestElement properties
public operator fun <ValueClass : TestElement> get(property: TestElementPropertyDescriptor<Schema, ValueClass>): ValueClass? =
public operator fun <ValueClass : TestElement> get(property: TestElementPropertyDescriptor<Schema, ValueClass>): ValueClass =
target[property]

public fun <ValueClass : TestElement> getOrNull(property: TestElementPropertyDescriptor<Schema, ValueClass>): ValueClass? =
target.getOrNull(property)

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline operator fun <ValueClass : TestElement> get(propertySelector: Schema.() -> TestElementPropertyDescriptor<Schema, ValueClass>): ValueClass? =
public inline operator fun <ValueClass : TestElement> get(propertySelector: Schema.() -> TestElementPropertyDescriptor<Schema, ValueClass>): ValueClass =
target[propertySelector(schema)]

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline fun <ValueClass : TestElement> getOrNull(propertySelector: Schema.() -> TestElementPropertyDescriptor<Schema, ValueClass>): ValueClass? =
target.getOrNull(propertySelector(schema))

public operator fun <ValueClass : TestElement> set(
property: TestElementPropertyDescriptor<Schema, ValueClass>,
value: ValueClass
value: ValueClass?
) {
target[property] = value
}

public inline operator fun <ValueClass : TestElement> set(
propertySelector: Schema.() -> TestElementPropertyDescriptor<Schema, ValueClass>,
value: ValueClass
value: ValueClass?
) {
target[propertySelector(schema)] = value
}

// Collection properties
public operator fun get(property: CollectionPropertyDescriptor<Schema>): Collection<JMeterProperty> =
public operator fun get(property: CollectionPropertyDescriptor<Schema>): CollectionProperty =
target[property]

public fun getOrNull(property: CollectionPropertyDescriptor<Schema>): CollectionProperty? =
target.getOrNull(property)

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline operator fun get(propertySelector: Schema.() -> CollectionPropertyDescriptor<Schema>): Collection<JMeterProperty> =
public inline operator fun get(propertySelector: Schema.() -> CollectionPropertyDescriptor<Schema>): CollectionProperty =
target[propertySelector(schema)]

public operator fun set(property: CollectionPropertyDescriptor<Schema>, value: Collection<*>) {
@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline fun getOrNull(propertySelector: Schema.() -> CollectionPropertyDescriptor<Schema>): CollectionProperty? =
target.getOrNull(propertySelector(schema))

public operator fun set(property: CollectionPropertyDescriptor<Schema>, value: Collection<*>?) {
target[property] = value
}

public inline operator fun set(
propertySelector: Schema.() -> CollectionPropertyDescriptor<Schema>,
value: Collection<*>
value: Collection<*>?
) {
target[propertySelector(schema)] = value
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class UseFunctionsTest {

// These assertions verify CollectionProperty behavior rather than USE_FUNCTIONS behavior
// However, we can't extract deeply-nested item right away
assertEquals(1, output.size) {
assertEquals(1, output.size()) {
"size of first level collection should be 1, actual: $output"
}
val nested = output.first()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void clear() {
* @return the header collection property
*/
public CollectionProperty getHeaders() {
return (CollectionProperty) getPropertyOrNull(getSchema().getHeaders());
return getOrNull(getSchema().getHeaders());
}

public int getColumnCount() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
import org.apache.jmeter.protocol.http.sampler.hc.LaxDeflateInputStream;
import org.apache.jmeter.protocol.http.sampler.hc.LaxGZIPInputStream;
import org.apache.jmeter.protocol.http.sampler.hc.LazyLayeredConnectionSocketFactory;
import org.apache.jmeter.protocol.http.util.ConversionUtils;
import org.apache.jmeter.protocol.http.util.EncoderCache;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
import org.apache.jmeter.protocol.http.util.HTTPConstants;
Expand Down Expand Up @@ -1508,7 +1509,9 @@ private static class ViewableFileBody extends FileBody {
private boolean hideFileData;

public ViewableFileBody(File file, ContentType contentType) {
super(file, contentType);
// Note: HttpClient4 does not support encoding the file name, so we explicitly encode it here
// See https://issues.apache.org/jira/browse/HTTPCLIENT-293
super(file, contentType, ConversionUtils.percentEncode(file.getName()));
hideFileData = false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.testelement.property.PropertyIterator;
import org.apache.jmeter.testelement.property.TestElementProperty;
import org.apache.jmeter.testelement.schema.PropertiesAccessor;
import org.apache.jmeter.testelement.schema.PropertyDescriptor;
import org.apache.jmeter.threads.JMeterContext;
Expand All @@ -92,6 +91,7 @@
import org.apache.oro.text.MalformedCachePatternException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Matcher;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -248,7 +248,6 @@ public abstract class HTTPSamplerBase extends AbstractSampler

// @see mergeFileProperties
// Must be private, as the file list needs special handling
private static final String FILE_ARGS = "HTTPsampler.Files"; // $NON-NLS-1$
// MIMETYPE is kept for backward compatibility with old test plans
private static final String MIMETYPE = "HTTPSampler.mimetype"; // $NON-NLS-1$
// FILE_NAME is kept for backward compatibility with old test plans
Expand Down Expand Up @@ -1829,18 +1828,14 @@ protected static String encodeBackSlashes(String value) {
* HTTPFileArgs object that stores file list to be uploaded.
*/
private void setHTTPFileArgs(HTTPFileArgs value) {
if (value.getHTTPFileArgCount() > 0) {
setProperty(new TestElementProperty(FILE_ARGS, value));
} else {
removeProperty(FILE_ARGS); // no point saving an empty list
}
set(getSchema().getFileArguments(), value.getHTTPFileArgCount() == 0 ? null : value);
}

/*
* Method to get files list to be uploaded.
*/
private HTTPFileArgs getHTTPFileArgs() {
return (HTTPFileArgs) getProperty(FILE_ARGS).getObjectValue();
private @Nullable HTTPFileArgs getHTTPFileArgs() {
return getOrNull(getSchema().getFileArguments());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.nio.file.Files;
import java.nio.file.Paths;

import org.apache.jmeter.protocol.http.util.ConversionUtils;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
import org.apache.jmeter.protocol.http.util.HTTPConstants;
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
Expand Down Expand Up @@ -391,7 +392,7 @@ private static void writeStartFileMultipart(OutputStream out, String filename,
write(out, "Content-Disposition: form-data; name=\""); // $NON-NLS-1$
write(out, nameField);
write(out, "\"; filename=\"");// $NON-NLS-1$
write(out, new File(filename).getName());
write(out, ConversionUtils.percentEncode(new File(filename).getName()));
writeln(out, "\""); // $NON-NLS-1$
writeln(out, "Content-Type: " + mimetype); // $NON-NLS-1$
writeln(out, "Content-Transfer-Encoding: binary"); // $NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apiguardian.api.API;

// @see TestHTTPUtils for unit tests

Expand Down Expand Up @@ -95,6 +96,23 @@ public static String getEncodingFromContentType(String contentType){
return charSet;
}

/**
* Encodes the string according to RFC7578 and RFC3986.
* The string is UTF-8 encoded, and non-ASCII bytes are represented as {@code %XX}.
* It is close to UrlEncode, however, {@code percentEncode} does not replace space with +.
* @param value input value to convert
* @return converted value
* @since 5.6
*/
@API(status = API.Status.MAINTAINED, since = "5.6")
public static String percentEncode(String value) {
try {
return new URI(null, null, value, null).toASCIIString();
} catch (URISyntaxException e) {
throw new IllegalStateException("Can't encode value " + value, e);
}
}

/**
* Generate an absolute URL from a possibly relative location,
* allowing for extraneous leading "../" segments.
Expand Down
Loading