Support variable for all JMS messages (bytes, object, ...) and sources (file, folder)

git-svn-id: https://svn.apache.org/repos/asf/jmeter/trunk@1783319 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Maxime Chassagneux 2017-02-16 23:50:00 +00:00
parent 20c9e229dd
commit 42dc0a9fb7
29 changed files with 1278 additions and 233 deletions

View File

@ -173,6 +173,10 @@ public class JLabeledChoice extends JPanel implements JLabeledField {
}
public void setChoiceListEnabled(boolean enabled) {
choiceList.setEnabled(enabled);
}
/**
* Set the text displayed in the label.
*

View File

@ -39,6 +39,7 @@ import org.apache.jmeter.protocol.jms.sampler.PublisherSampler;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.gui.JLabeledChoice;
import org.apache.jorphan.gui.JLabeledPasswordField;
import org.apache.jorphan.gui.JLabeledTextField;
@ -56,7 +57,7 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
/** Take source from a random file */
public static final String USE_RANDOM_RSC = "jms_use_random_file"; //$NON-NLS-1$
/** Take source from the text area */
private static final String USE_TEXT_RSC = "jms_use_text"; //$NON-NLS-1$
public static final String USE_TEXT_RSC = "jms_use_text"; //$NON-NLS-1$
/** Create a TextMessage */
public static final String TEXT_MSG_RSC = "jms_text_message"; //$NON-NLS-1$
@ -111,6 +112,8 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
private final JLabeledRadioI18N msgChoice = new JLabeledRadioI18N("jms_message_type", MSGTYPES_ITEMS, TEXT_MSG_RSC); //$NON-NLS-1$
private JLabeledChoice fileEncoding;
private final JCheckBox useNonPersistentDelivery = new JCheckBox(JMeterUtils.getResString("jms_use_non_persistent_delivery"),false); //$NON-NLS-1$
// These are the names of properties used to define the labels
@ -180,6 +183,7 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
sampler.setInputFile(messageFile.getFilename());
sampler.setRandomPath(randomFile.getFilename());
sampler.setConfigChoice(configChoice.getText());
sampler.setFileEncoding(fileEncoding.getText());
sampler.setMessageChoice(msgChoice.getText());
sampler.setIterations(iterations.getText());
sampler.setUseAuth(useAuth.isSelected());
@ -218,6 +222,13 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
mainPanel.add(configChoice);
msgChoice.setLayout(new BoxLayout(msgChoice, BoxLayout.X_AXIS));
mainPanel.add(msgChoice);
fileEncoding = new JLabeledChoice(JMeterUtils.getResString("content_encoding") + "\u00A0\u00A0", // $NON-NLS-1$
PublisherSampler.getSupportedEncodings(), true, false);
fileEncoding.setLayout(new BoxLayout(fileEncoding, BoxLayout.X_AXIS));
fileEncoding.add(Box.createHorizontalGlue());
mainPanel.add(fileEncoding);
mainPanel.add(messageFile);
mainPanel.add(randomFile);
@ -249,6 +260,7 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
messageFile.setFilename(""); // $NON-NLS-1$
randomFile.setFilename(""); // $NON-NLS-1$
msgChoice.setText(""); // $NON-NLS-1$
fileEncoding.setSelectedIndex(0);
configChoice.setText(USE_TEXT_RSC);
updateConfig(USE_TEXT_RSC);
msgChoice.setText(TEXT_MSG_RSC);
@ -281,6 +293,7 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
randomFile.setFilename(sampler.getRandomPath());
configChoice.setText(sampler.getConfigChoice());
msgChoice.setText(sampler.getMessageChoice());
fileEncoding.setText(sampler.getFileEncoding());
iterations.setText(sampler.getIterations());
expiration.setText(sampler.getExpiration());
jmsErrorReconnectOnCodes.setText(sampler.getReconnectionErrorCodes());
@ -315,6 +328,12 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
jmsPwd.setEnabled(useAuth.isSelected() && useAuth.isEnabled());
}
}
private void updateFileEncoding() {
boolean isTextMode = USE_TEXT_RSC.equals(configChoice.getText());
boolean isObjectType = OBJECT_MSG_RSC.equals(msgChoice.getText());
fileEncoding.setChoiceListEnabled(!isTextMode && !isObjectType);
}
/**
* Update choice contains the actual logic for hiding or showing Textarea if Bytes message
* is selected
@ -333,6 +352,7 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
configChoice.resetButtons(CONFIG_ITEMS, oldChoice);
textMessage.setEnabled(true);
}
updateFileEncoding();
validate();
}
/**
@ -355,6 +375,7 @@ public class JMSPublisherGui extends AbstractSamplerGui implements ChangeListene
messageFile.enableFile(true);
randomFile.enableFile(false);
}
updateFileEncoding();
}
/**

View File

@ -17,19 +17,20 @@
package org.apache.jmeter.protocol.jms.sampler;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
@ -43,23 +44,53 @@ import org.apache.jmeter.protocol.jms.client.ClientPool;
import org.apache.jmeter.protocol.jms.client.InitialContextFactory;
import org.apache.jmeter.protocol.jms.client.Publisher;
import org.apache.jmeter.protocol.jms.control.gui.JMSPublisherGui;
import org.apache.jmeter.protocol.jms.sampler.render.MessageRenderer;
import org.apache.jmeter.protocol.jms.sampler.render.Renderers;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.services.FileServer;
import org.apache.jmeter.testelement.TestStateListener;
import org.apache.jmeter.testelement.property.TestElementProperty;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.io.TextFile;
import org.apache.jorphan.util.JOrphanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.thoughtworks.xstream.XStream;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
/**
* This class implements the JMS Publisher sampler.
*/
public class PublisherSampler extends BaseJMSSampler implements TestStateListener {
/** Encoding value to sent data as is (no variabilisation) **/
public static final String RAW_DATA = "<RAW>";
/** Encoding value to sent parsed data but read with default system encoding **/
public static final String DEFAULT_ENCODING = "<DEFAULT>";
/** Constant for system default encodings **/
public static final Set<String> NO_ENCODING = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(RAW_DATA, DEFAULT_ENCODING)));
/** Init available encoding using constants, then JVM standard ones **/
public static String[] getSupportedEncodings() {
// Only get JVM standard charsets
return Stream.concat(
NO_ENCODING.stream(),
Arrays
.stream(StandardCharsets.class.getDeclaredFields())
.filter(f -> Modifier.isStatic(f.getModifiers()) && Modifier.isPublic(f.getModifiers()) && f.getType() == Charset.class)
.map(f -> {
try {
return (Charset) f.get(null);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
})
.map(Charset::displayName)
.sorted()
)
.toArray(size -> new String[size]);
}
private static final long serialVersionUID = 233L;
private static final Logger log = LoggerFactory.getLogger(PublisherSampler.class);
@ -74,15 +105,22 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
private static final String CONFIG_CHOICE = "jms.config_choice"; //$NON-NLS-1$
private static final String MESSAGE_CHOICE = "jms.config_msg_type"; //$NON-NLS-1$
private static final String NON_PERSISTENT_DELIVERY = "jms.non_persistent"; //$NON-NLS-1$
private static final String JMS_PROPERTIES = "jms.jmsProperties"; // $NON-NLS-1$
private static final String JMS_PRIORITY = "jms.priority"; // $NON-NLS-1$
private static final String JMS_EXPIRATION = "jms.expiration"; // $NON-NLS-1$
private static final String JMS_FILE_ENCODING = "jms.file_encoding"; // $NON-NLS-1$
/** File extensions for text files **/
private static final String[] EXT_FILE_TEXT = { ".txt", ".obj" };
/** File extensions for binary files **/
private static final String[] EXT_FILE_BIN = { ".dat" };
//--
// Does not need to be synch. because it is only accessed from the sampler thread
@ -91,19 +129,8 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
private static final FileServer FSERVER = FileServer.getFileServer();
// Cache for file. Only used by sample() in a single thread
private String file_contents = null;
// Cache for object-message, only used when parsing from a file because in text-area
// property replacement might have been used
private Serializable object_msg_file_contents = null;
// Cache for bytes-message, only used when parsing from a file
private byte[] bytes_msg_file_contents = null;
// Cached file name
private String cachedFileName;
public PublisherSampler() {
}
/** File cache handler **/
private Cache<Object,Object> fileCache = null;
/**
* the implementation calls testStarted() without any parameters.
@ -137,11 +164,12 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
/**
* initialize the Publisher client.
* @throws JMSException
* @throws NamingException
* @throws JMSException
* @throws NamingException
*
*/
private void initClient() throws JMSException, NamingException {
configureIsReconnectErrorCode();
publisher = new Publisher(getUseJNDIPropertiesAsBoolean(), getJNDIInitialContextFactory(),
getProviderUrl(), getConnectionFactory(), getDestination(), isUseAuth(), getUsername(),
@ -158,6 +186,12 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
*/
@Override
public SampleResult sample() {
String configChoice = getConfigChoice();
if (fileCache == null) {
Cache<Object, Object> newCache = buildCache(configChoice);
fileCache = newCache;
}
SampleResult result = new SampleResult();
result.setSampleLabel(getName());
result.setSuccessful(false); // Assume it will fail
@ -175,34 +209,34 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
int loop = getIterationCount();
result.sampleStart();
String type = getMessageChoice();
try {
Map<String, Object> msgProperties = getJMSProperties().getJmsPropertysAsMap();
int deliveryMode = getUseNonPersistentDelivery() ? DeliveryMode.NON_PERSISTENT : DeliveryMode.PERSISTENT;
int deliveryMode = getUseNonPersistentDelivery() ? DeliveryMode.NON_PERSISTENT : DeliveryMode.PERSISTENT;
int priority = Integer.parseInt(getPriority());
long expiration = Long.parseLong(getExpiration());
for (int idx = 0; idx < loop; idx++) {
Message msg;
if (JMSPublisherGui.TEXT_MSG_RSC.equals(type)){
String tmsg = getMessageContent();
Message msg = publisher.publish(tmsg, getDestination(), msgProperties, deliveryMode, priority, expiration);
String tmsg = getRenderedContent(String.class, EXT_FILE_TEXT);
msg = publisher.publish(tmsg, getDestination(), msgProperties, deliveryMode, priority, expiration);
buffer.append(tmsg);
Utils.messageProperties(propBuffer, msg);
} else if (JMSPublisherGui.MAP_MSG_RSC.equals(type)){
Map<String, Object> m = getMapContent();
Message msg = publisher.publish(m, getDestination(), msgProperties, deliveryMode, priority, expiration);
Utils.messageProperties(propBuffer, msg);
@SuppressWarnings("unchecked")
Map<String,Object> map = getRenderedContent(Map.class, EXT_FILE_TEXT);
Map<String, Object> m = map;
msg = publisher.publish(m, getDestination(), msgProperties, deliveryMode, priority, expiration);
} else if (JMSPublisherGui.OBJECT_MSG_RSC.equals(type)){
Serializable omsg = getObjectContent();
Message msg = publisher.publish(omsg, getDestination(), msgProperties, deliveryMode, priority, expiration);
Utils.messageProperties(propBuffer, msg);
Serializable omsg = getRenderedContent(Serializable.class, EXT_FILE_TEXT);
msg = publisher.publish(omsg, getDestination(), msgProperties, deliveryMode, priority, expiration);
} else if (JMSPublisherGui.BYTES_MSG_RSC.equals(type)){
byte[] bmsg = getBytesContent();
Message msg = publisher.publish(bmsg, getDestination(), msgProperties, deliveryMode, priority, expiration);
Utils.messageProperties(propBuffer, msg);
byte[] bmsg = getRenderedContent(byte[].class, EXT_FILE_BIN);
msg = publisher.publish(bmsg, getDestination(), msgProperties, deliveryMode, priority, expiration);
} else {
throw new JMSException(type+ " is not recognised");
throw new JMSException(type+ " is not recognised");
}
Utils.messageProperties(propBuffer, msg);
}
result.setResponseCodeOK();
result.setResponseMessage(loop + " messages published");
@ -215,7 +249,7 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
} catch (Exception e) {
handleError(result, e, false);
} finally {
result.sampleEnd();
result.sampleEnd();
}
return result;
}
@ -250,198 +284,54 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
result.setResponseData(writer.toString(), "UTF-8");
}
private Map<String, Object> getMapContent() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Map<String,Object> m = new HashMap<>();
String text = getMessageContent();
String[] lines = text.split("\n");
for (String line : lines){
String[] parts = line.split(",",3);
if (parts.length != 3) {
throw new IllegalArgumentException("line must have 3 parts: "+line);
}
String name = parts[0];
String type = parts[1];
if (!type.contains(".")){// Allow shorthand names
type = "java.lang."+type;
}
String value = parts[2];
Object obj;
if (type.equals("java.lang.String")){
obj = value;
} else {
Class <?> clazz = Class.forName(type);
Method method = clazz.getMethod("valueOf", String.class);
obj = method.invoke(clazz, value);
}
m.put(name, obj);
protected static Cache<Object, Object> buildCache(String configChoice) {
Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder();
switch (configChoice) {
case JMSPublisherGui.USE_FILE_RSC:
cacheBuilder.maximumSize(1);
break;
default:
cacheBuilder.expireAfterWrite(0, TimeUnit.MILLISECONDS).maximumSize(0);
}
Cache<Object, Object> newCache = cacheBuilder.build();
return newCache;
}
/** Gets file path to use **/
private String getFilePath(String... ext) {
switch (getConfigChoice()) {
case JMSPublisherGui.USE_FILE_RSC:
return getInputFile();
case JMSPublisherGui.USE_RANDOM_RSC:
String fname = FSERVER.getRandomFile(getRandomPath(), ext).getAbsolutePath();
return fname;
default:
throw new IllegalArgumentException("Type of input not handled:" + getConfigChoice());
}
return m;
}
/**
* Method will check the setting and get the contents for the message.
/** Look-up renderer and get appropriate value
*
* @return the contents for the message
*/
private String getMessageContent() {
if (getConfigChoice().equals(JMSPublisherGui.USE_FILE_RSC)) {
// in the case the test uses a file, we set it locally and
// prevent loading the file repeatedly
// if the file name changes we reload it
if (file_contents == null || !Objects.equals(cachedFileName, getInputFile())) {
cachedFileName = getInputFile();
file_contents = getFileContent(getInputFile());
}
return file_contents;
} else if (getConfigChoice().equals(JMSPublisherGui.USE_RANDOM_RSC)) {
// Maybe we should consider creating a global cache for the
// random files to make JMeter more efficient.
String fname = FSERVER.getRandomFile(getRandomPath(), new String[] { ".txt", ".obj" })
.getAbsolutePath();
return getFileContent(fname);
* @param type Message type to render
* @param fileExts File extensions for directory mode.
**/
private <T> T getRenderedContent(Class<T> type, String[] fileExts) {
MessageRenderer<T> renderer = Renderers.getInstance(type);
if (getConfigChoice().equals(JMSPublisherGui.USE_TEXT_RSC)) {
return renderer.getValueFromText(getTextMessage());
} else {
return getTextMessage();
return renderer.getValueFromFile(getFilePath(fileExts), getFileEncoding(), !isRaw(), fileCache);
}
}
/**
* The implementation uses TextFile to load the contents of the file and
* returns a string.
*
* @param path path to the file to read in
* @return the contents of the file
* Specified if value must be parsed or not.
* @return <code>true</code> if value must be sent as-is.
*/
public String getFileContent(String path) {
TextFile tf = new TextFile(path);
return tf.getText();
private boolean isRaw() {
return RAW_DATA.equals(getFileEncoding());
}
/**
* This method will load the contents for the JMS Object Message.
* The contents are either loaded from file (might be cached), random file
* or from the GUI text-area.
*
* @return Serialized object as loaded from the specified input file
*/
private Serializable getObjectContent() {
if (getConfigChoice().equals(JMSPublisherGui.USE_FILE_RSC)) {
// in the case the test uses a file, we set it locally and
// prevent loading the file repeatedly
// if the file name changes we reload it
if (object_msg_file_contents == null || !Objects.equals(cachedFileName, getInputFile())) {
cachedFileName = getInputFile();
object_msg_file_contents = getFileObjectContent(getInputFile());
}
return object_msg_file_contents;
} else if (getConfigChoice().equals(JMSPublisherGui.USE_RANDOM_RSC)) {
// Maybe we should consider creating a global cache for the
// random files to make JMeter more efficient.
final String fname = FSERVER.getRandomFile(getRandomPath(), new String[] {".txt", ".obj"})
.getAbsolutePath();
return getFileObjectContent(fname);
} else {
final String xmlMessage = getTextMessage();
return transformXmlToObjectMessage(xmlMessage);
}
}
/**
* This method will load the contents for the JMS BytesMessage.
* The contents are either loaded from file (might be cached), random file
*
* @return byte[] as loaded from the specified input file
* @since 2.9
*/
private byte[] getBytesContent() {
if (getConfigChoice().equals(JMSPublisherGui.USE_FILE_RSC)) {
// in the case the test uses a file, we set it locally and
// prevent loading the file repeatedly
// if the file name changes we reload it
if (bytes_msg_file_contents == null || !Objects.equals(cachedFileName, getInputFile())) {
cachedFileName = getInputFile();
bytes_msg_file_contents = getFileBytesContent(getInputFile());
}
return bytes_msg_file_contents;
} else if (getConfigChoice().equals(JMSPublisherGui.USE_RANDOM_RSC)) {
final String fname = FSERVER.getRandomFile(getRandomPath(), new String[] {".dat"})
.getAbsolutePath();
return getFileBytesContent(fname);
} else {
throw new IllegalArgumentException("Type of input not handled:" + getConfigChoice());
}
}
/**
* Try to load an object from a provided file, so that it can be used as body
* for a JMS message.
* An {@link IllegalStateException} will be thrown if loading the object fails.
*
* @param path Path to the file that will be serialized
* @return byte[] instance
* @since 2.9
*/
private static byte[] getFileBytesContent(final String path) {
InputStream inputStream = null;
try {
File file = new File(path);
inputStream = new BufferedInputStream(new FileInputStream(file));
return IOUtils.toByteArray(inputStream, (int)file.length());
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e);
throw new IllegalStateException("Unable to load file:'"+path+"'", e);
} finally {
JOrphanUtils.closeQuietly(inputStream);
}
}
/**
* Try to load an object from a provided file, so that it can be used as body
* for a JMS message.
* An {@link IllegalStateException} will be thrown if loading the object fails.
*
* @param path Path to the file that will be serialized
* @return Serialized object instance
*/
private static Serializable getFileObjectContent(final String path) {
Serializable readObject = null;
InputStream inputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(path));
XStream xstream = new XStream();
readObject = (Serializable) xstream.fromXML(inputStream, readObject);
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e);
throw new IllegalStateException("Unable to load object instance from file:'"+path+"'", e);
} finally {
JOrphanUtils.closeQuietly(inputStream);
}
return readObject;
}
/**
* Try to load an object via XStream from XML text, so that it can be used as body
* for a JMS message.
* An {@link IllegalStateException} will be thrown if transforming the XML to an object fails.
*
* @param xmlMessage String containing XML text as input for the transformation
* @return Serialized object instance
*/
private static Serializable transformXmlToObjectMessage(final String xmlMessage) {
Serializable readObject = null;
try {
XStream xstream = new XStream();
readObject = (Serializable) xstream.fromXML(xmlMessage, readObject);
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e);
throw new IllegalStateException("Unable to load object instance from text", e);
}
return readObject;
}
// ------------- get/set properties ----------------------//
/**
* set the source of the message
@ -469,7 +359,7 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
public String getConfigChoice() {
// Allow for the old JMX file which used the local language string
String config = getPropertyAsString(CONFIG_CHOICE);
if (config.equals(USE_FILE_LOCALNAME)
if (config.equals(USE_FILE_LOCALNAME)
|| config.equals(JMSPublisherGui.USE_FILE_RSC)){
return JMSPublisherGui.USE_FILE_RSC;
}
@ -565,7 +455,7 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
return priority;
}
}
public void setPriority(String s) {
// Bug 59173
if (Utils.DEFAULT_PRIORITY_4.equals(s)) {
@ -573,7 +463,7 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
}
setProperty(JMS_PRIORITY, s); // always need to save the field
}
public void setExpiration(String s) {
// Bug 59173
if (Utils.DEFAULT_NO_EXPIRY.equals(s)) {
@ -581,14 +471,14 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
}
setProperty(JMS_EXPIRATION, s); // always need to save the field
}
/**
* @param value boolean use NON_PERSISTENT
*/
public void setUseNonPersistentDelivery(boolean value) {
setProperty(NON_PERSISTENT_DELIVERY, value, false);
}
/**
* @return true if NON_PERSISTENT delivery must be used
*/
@ -596,7 +486,7 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
return getPropertyAsBoolean(NON_PERSISTENT_DELIVERY, false);
}
/**
/**
* @return {@link JMSProperties} JMS Properties
*/
public JMSProperties getJMSProperties() {
@ -614,11 +504,33 @@ public class PublisherSampler extends BaseJMSSampler implements TestStateListene
}
return jmsProperties;
}
/**
* @param jmsProperties JMS Properties
*/
public void setJMSProperties(JMSProperties jmsProperties) {
setProperty(new TestElementProperty(JMS_PROPERTIES, jmsProperties));
}
/**
* Gets file encoding to use. If {@value #RAW_DATA}, content isn't parsed.
* @return File encoding.
* @see #RAW_DATA
* @see #DEFAULT_ENCODING
* @see #getSupportedEncodings()
*/
public String getFileEncoding() {
return getPropertyAsString(JMS_FILE_ENCODING, RAW_DATA);
}
/**
* Sets file encoding to use. If {@value #RAW_DATA}, content isn't parsed.
* @param fileEncoding File encoding.
* @see #RAW_DATA
* @see #DEFAULT_ENCODING
* @see #getSupportedEncodings()
*/
public void setFileEncoding(String fileEncoding) {
setProperty(JMS_FILE_ENCODING, fileEncoding, RAW_DATA);
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.protocol.jms.sampler.render;
import static java.lang.String.format;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.apache.jmeter.protocol.jms.control.gui.JMSPublisherGui;
import com.github.benmanes.caffeine.cache.Cache;
class BinaryMessageRenderer implements MessageRenderer<byte[]> {
private TextMessageRenderer delegate;
public BinaryMessageRenderer(TextMessageRenderer delegate) {
this.delegate = delegate;
}
@Override
public byte[] getValueFromText(String text) {
throw new UnsupportedOperationException(format("Type of input not handled: %s", JMSPublisherGui.USE_TEXT_RSC));
}
@Override
public byte[] getValueFromFile(String filename, String encoding, boolean hasVariable, Cache<Object,Object> cache) {
byte[] bytes;
if (hasVariable) {
String stringValue = delegate.getValueFromFile(filename, encoding, hasVariable, cache);
try {
bytes = stringValue.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
} else {
bytes = (byte[]) cache.get(filename, _p -> getContent(filename));
}
return bytes;
}
byte[] getContent(String filename) {
try {
return Files.readAllBytes(Paths.get(filename));
} catch (IOException e) {
throw new RuntimeException(format("Can't read content of %s", filename), e);
}
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.protocol.jms.sampler.render;
import java.util.Objects;
/** File specification for {@link TextMessageRenderer} **/
class FileKey {
private final String filename;
private final String encoding;
public FileKey(String filename, String encoding) {
this.filename = filename;
this.encoding = encoding;
}
public String getFilename() {
return filename;
}
public String getEncoding() {
return encoding;
}
@Override
public int hashCode() {
return Objects.hashCode(filename);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof FileKey)) {
return false;
}
FileKey that = (FileKey) obj;
return Objects.equals(this.filename, that.filename);
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.protocol.jms.sampler.render;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import com.github.benmanes.caffeine.cache.Cache;
public class MapMessageRenderer implements MessageRenderer<Map<String,Object>> {
private TextMessageRenderer delegate;
public MapMessageRenderer(TextMessageRenderer delegate) {
this.delegate = delegate;
}
@Override
public Map<String, Object> getValueFromText(String text) {
Map<String,Object> m = new HashMap<>();
String[] lines = text.split("\n");
for (String line : lines){
String[] parts = line.split(",",3);
if (parts.length != 3) {
throw new IllegalArgumentException("line must have 3 parts: "+line);
}
String name = parts[0];
String type = parts[1];
if (!type.contains(".")){// Allow shorthand names
type = "java.lang."+type;
}
String value = parts[2];
Object obj;
if (type.equals("java.lang.String")){
obj = value;
} else {
try {
Class <?> clazz = Class.forName(type);
Method method = clazz.getMethod("valueOf", new Class<?>[]{String.class});
obj = method.invoke(clazz, value);
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(String.format("Can't convert %s to object", line), e);
}
}
m.put(name, obj);
}
return m;
}
@Override
public Map<String, Object> getValueFromFile(String filename, String encoding, boolean hasVariable, Cache<Object,Object> cache) {
String text = delegate.getValueFromFile(filename, encoding, hasVariable, cache);
return getValueFromText(text);
}
}

View File

@ -0,0 +1,27 @@
/*
* 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.protocol.jms.sampler.render;
import com.github.benmanes.caffeine.cache.Cache;
public interface MessageRenderer<T> {
/** Convert text to expected type **/
T getValueFromText(String text);
/** Read text from file, eventually replace variables, then convert it. Cached content depends if variabilisation is active or not. **/
T getValueFromFile(String filename, String encoding, boolean hasVariable, Cache<Object,Object> cache);
}

View File

@ -0,0 +1,106 @@
/*
* 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.protocol.jms.sampler.render;
import static java.lang.String.format;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.jmeter.protocol.jms.sampler.PublisherSampler;
import com.github.benmanes.caffeine.cache.Cache;
import com.thoughtworks.xstream.XStream;
class ObjectMessageRenderer implements MessageRenderer<Serializable> {
TextMessageRenderer delegate;
public ObjectMessageRenderer(TextMessageRenderer delegate) {
this.delegate = delegate;
}
@Override
public Serializable getValueFromFile(String filename, String encoding, boolean hasVariable, Cache<Object,Object> cache) {
Serializable value;
if (hasVariable) {
value = getInterpretedContent(filename, encoding, hasVariable, cache);
} else {
value = (Serializable) cache.get(filename, _p -> getContent(filename));
}
return value;
}
/**
* Try to load an object via XStream from XML text, so that it can be used as body
* for a JMS message.
* An {@link IllegalStateException} will be thrown if transforming the XML to an object fails.
*
* @param xmlMessage String containing XML text as input for the transformation
* @return Serialized object instance
*/
@Override
public Serializable getValueFromText(final String xmlMessage) {
Serializable readObject = null;
try {
XStream xstream = new XStream();
readObject = (Serializable) xstream.fromXML(xmlMessage, readObject);
} catch (Exception e) {
throw new IllegalStateException("Unable to load object instance from text", e);
}
return readObject;
}
/**
* <p>Gets content with variable replaced.</p>
* <p>If encoding {@link PublisherSampler#DEFAULT_ENCODING isn't provided}, try to find it.</p>
* <p>Only raw text is cached, neither interpreted text, neither parsed object.</p>
*/
protected Serializable getInterpretedContent(String filename, String encoding, boolean hasVariable, Cache<Object,Object> cache) {
Serializable value;
if (PublisherSampler.DEFAULT_ENCODING.equals(encoding)) {
encoding = findEncoding(filename);
}
String stringValue = delegate.getValueFromFile(filename, encoding, hasVariable, cache);
value = (Serializable) new XStream().fromXML(stringValue);
return value;
}
/** Try to determine encoding based on XML prolog, if none <code>null</code> is returned. **/
protected String findEncoding(String filename) {
XMLInputFactory factory = XMLInputFactory.newFactory();
try (FileInputStream input = new FileInputStream(filename)) {
XMLStreamReader reader = factory.createXMLStreamReader(input);
return reader.getEncoding();
} catch (IOException|XMLStreamException e) {
throw new RuntimeException(format("Unable to read %s", filename), e);
}
}
protected Serializable getContent(String filename) {
Serializable object = (Serializable) new XStream().fromXML(new File(filename));
return object;
}
}

View File

@ -0,0 +1,72 @@
/*
* 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.protocol.jms.sampler.render;
import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Renderer singleton.
*/
enum RendererFactory {
INSTANCE;
public static RendererFactory getInstance() {
return INSTANCE;
}
private TextMessageRenderer text = new TextMessageRenderer();
private BinaryMessageRenderer binary = new BinaryMessageRenderer(text);
private ObjectMessageRenderer object = new ObjectMessageRenderer(text);
private MapMessageRenderer map = new MapMessageRenderer(text);
/** Registred renderers **/
private Map<Class<?>, MessageRenderer<?>> renderers;
{
Map<Class<?>, MessageRenderer<?>> writable = new LinkedHashMap<>();
writable.put(String.class, text);
writable.put(byte[].class, binary);
writable.put(Serializable.class, object);
writable.put(Map.class, map);
renderers = Collections.unmodifiableMap(writable);
}
public TextMessageRenderer getText() {
return text;
}
public BinaryMessageRenderer getBinary() {
return binary;
}
public ObjectMessageRenderer getObject() {
return object;
}
public MapMessageRenderer getMap() {
return map;
}
@SuppressWarnings("unchecked")
public <T> MessageRenderer<T> getInstance(Class<T> type) {
return (MessageRenderer<T>) renderers.get(type);
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.protocol.jms.sampler.render;
import java.io.Serializable;
import java.util.Map;
/**
* Renderer API entry point.
*/
public interface Renderers {
public static MessageRenderer<String> getText() {
return RendererFactory.getInstance().getText();
}
public static MessageRenderer<byte[]> getBinary() {
return RendererFactory.getInstance().getBinary();
}
public static MessageRenderer<Serializable> getObject() {
return RendererFactory.getInstance().getObject();
}
public static MessageRenderer<Map<String,Object>> getMap() {
return RendererFactory.getInstance().getMap();
}
public static <T> MessageRenderer<T> getInstance(Class<T> type) {
return RendererFactory.getInstance().getInstance(type);
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.protocol.jms.sampler.render;
import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jorphan.io.TextFile;
import com.github.benmanes.caffeine.cache.Cache;
class TextMessageRenderer implements MessageRenderer<String> {
@Override
public String getValueFromText(String text) {
return text;
}
@Override
public String getValueFromFile(String filename, String encoding, boolean hasVariable, Cache<Object,Object> cache) {
String text = (String) cache.get(new FileKey(filename, encoding), key -> getContent((FileKey)key));
if (hasVariable) {
text = new CompoundVariable(text).execute();
}
return text;
}
String getContent(FileKey key) {
return new TextFile(key.getFilename(), key.getEncoding()).getText();
}
}

View File

@ -0,0 +1,23 @@
/*
* 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 contains all renderer for JMS publisher.
* @see Renderers
* @see MessageRenderer
*/
package org.apache.jmeter.protocol.jms.sampler.render;

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
<org.apache.jmeter.protocol.jms.sampler.render.Person><name>e<EFBFBD><EFBFBD></name></org.apache.jmeter.protocol.jms.sampler.render.Person>

View File

@ -0,0 +1 @@
<org.apache.jmeter.protocol.jms.sampler.render.Person><name>Doe</name></org.apache.jmeter.protocol.jms.sampler.render.Person>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="Windows-1252"?>
<org.apache.jmeter.protocol.jms.sampler.render.Person><name>e<EFBFBD><EFBFBD></name></org.apache.jmeter.protocol.jms.sampler.render.Person>

View File

@ -0,0 +1 @@
<org.apache.jmeter.protocol.jms.sampler.render.Person><name>eéè€</name></org.apache.jmeter.protocol.jms.sampler.render.Person>

View File

@ -0,0 +1 @@
${oneVar}

View File

@ -0,0 +1 @@
éè€

View File

@ -0,0 +1,60 @@
/*
* 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.protocol.jms.sampler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import java.util.Locale;
import org.apache.jmeter.protocol.jms.control.gui.JMSPublisherGui;
import org.apache.jmeter.util.JMeterUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.github.benmanes.caffeine.cache.Cache;
/**
*
*/
public class PublisherSamplerTest {
@Before
public void initJMeter() {
JMeterUtils.setLocale(new Locale("ignoreResources"));
}
@After
public void resetJMeter() {
JMeterUtils.setLocale(Locale.ENGLISH);
}
@Test
public void noopCache() {
Cache<Object,Object> noopCache = PublisherSampler.buildCache(JMSPublisherGui.USE_RANDOM_RSC);
assertEquals(0, noopCache.estimatedSize());
String key = "key";
String val1 = "1st time";
assertSame(val1, noopCache.get(key, k -> val1));
String val2 = "2nd call";
assertSame(val2, noopCache.get(key, k -> val2));
}
}

View File

@ -0,0 +1,123 @@
/*
* 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.protocol.jms.sampler.render;
import static java.lang.String.format;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class BinaryMessageRendererTest extends MessageRendererTest<byte[]> {
@Rule
public ExpectedException error = ExpectedException.none();
BinaryMessageRenderer render = RendererFactory.getInstance().getBinary();
@Override
protected MessageRenderer<byte[]> getRenderer() {
return render;
}
@Test(expected=UnsupportedOperationException.class)
public void getValueFromText() {
render.getValueFromText("");
}
@Test
public void readUTF8File() {
assertContent("utf8.txt", "UTF-8");
}
@Test
public void readCP1252File() {
assertContent("cp1252.txt", "Cp1252");
}
private void assertContent(String resource, String encoding) {
String filename = getResourceFile(resource);
byte[] actual = render.getContent(filename);
try {
assertArrayEquals("éè€".getBytes(encoding), actual);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@Test
public void readNonExistingContent() {
error.expect(RuntimeException.class);
error.expectCause(instanceOf(IOException.class));
error.expectMessage("Can't read content of __file_that_may_not_exists_else_it_will_fail");
render.getContent("__file_that_may_not_exists_else_it_will_fail");
}
@Test
public void getValueFromFile_withNoVar() {
String text = format("éè€%n");
assertValueFromFile(text, "utf8.txt", true);
assertCacheContentInString(text);
}
@Test
public void getValueFromFile_withOneVar() {
String value = "éè€";
jmeterCtxService.get().getVariables().put("oneVar", value);
assertValueFromFile(format("%s%n", value), "oneVar.txt", true);
assertCacheContentInString(format("${oneVar}%n"));
}
@Test
public void getValueFromFile_withInvalidEncoding() {
error.expect(RuntimeException.class);
error.expectCause(instanceOf(UnsupportedEncodingException.class));
render.getValueFromFile(getResourceFile("utf8.txt"), "banana", true, cache);
}
@Test
public void getValueFromFile_inRawMode() {
String text = "${oneVar}";
assertValueFromFile(text, "oneVar.txt", false);
assertCacheContentInBytes(text);
}
protected void assertValueFromFile(String expected, String resource, boolean hasVariable) {
assertValueFromFile(actual -> assertBytesEquals(expected, actual), resource, hasVariable);
}
protected void assertCacheContentInBytes(String expected) {
assertBytesEquals(expected, (byte[]) cacheContent.getValue());
}
protected void assertCacheContentInString(String expected) {
assertEquals(expected, cacheContent.getValue());
}
protected void assertBytesEquals(String expected, byte[] actual) {
assertArrayEquals(expected.getBytes(StandardCharsets.UTF_8), actual);
}
}

View File

@ -0,0 +1,74 @@
/*
* 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.protocol.jms.sampler.render;
import static java.lang.String.format;
import java.util.AbstractMap;
import java.util.Map.Entry;
import java.util.function.Consumer;
import java.util.function.Function;
import org.apache.jmeter.protocol.jms.sampler.cache.Cache;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.threads.JMeterContextServiceHelper;
import org.apache.jmeter.threads.JMeterVariables;
import org.junit.Rule;
/**
*
*/
public abstract class MessageRendererTest<T> {
@SuppressWarnings("rawtypes")
protected Entry cacheContent;
protected Cache cache = new Cache() {
@Override
public void put(Object key, Object value) {
cacheContent = new AbstractMap.SimpleImmutableEntry<>(key, value);
}
@Override
public <K, V> V get(K key, Function<K, V> get) {
V value = get.apply(key);
cacheContent = new AbstractMap.SimpleImmutableEntry<>(key, value);
return value;
}
};
@Rule
public JMeterContextServiceHelper jmeterCtxService = new JMeterContextServiceHelper() {
@Override
protected void initContext(JMeterContext jMeterContext) {
jMeterContext.setVariables(new JMeterVariables());
}
};
protected abstract MessageRenderer<T> getRenderer();
protected String getResourceFile(String resource) {
return format("test/resources/%s/%s", getClass().getPackage().getName().replace('.', '/'), resource);
}
protected void assertValueFromFile(Consumer<T> assertion, String resource, boolean hasVariable) {
String filename = getResourceFile(resource);
T actual = getRenderer().getValueFromFile(filename, "UTF-8", hasVariable, cache);
assertion.accept(actual);
}
}

View File

@ -0,0 +1,99 @@
/*
* 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.protocol.jms.sampler.render;
import static java.lang.String.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import java.io.Serializable;
import org.apache.jmeter.protocol.jms.sampler.PublisherSampler;
import org.junit.Test;
/**
*
*/
public class ObjectMessageRendererTest extends MessageRendererTest<Serializable> {
private ObjectMessageRenderer render = RendererFactory.getInstance().getObject();
@Override
public ObjectMessageRenderer getRenderer() {
return render;
}
@Test
public void getValueFromText() {
Serializable object = render.getValueFromText(getDoeContent());
assertObject(object, "Doe");
}
private void assertObject(Serializable object, String name) {
assertNotNull("object", object);
assertEquals("object.class", Person.class, object.getClass());
Person p = (Person) object;
assertEquals("object.name", name, p.getName());
}
@Test
public void getValueFromFile_inRawMode() {
assertValueFromFile(object -> {
assertObject(object, "Doe");
Person p = (Person) object;
assertSame("cache", p, cacheContent.getValue());
}, "object_doe.xml", false);
}
@Test
public void getValueFromFile_withForcedEncoding() {
String filename = getResourceFile("object_cp1252.xml");
Serializable object = getRenderer().getValueFromFile(filename, "Cp1252", true, cache);
assertObject(object, "eéè€");
assertEquals("cache", format("%s%n", getUnicodeContent()), cacheContent.getValue());
}
@Test
public void getValueFromFile_withDefaultEncodingAndNoProlog() {
String filename = getResourceFile("object_utf8.xml");
Serializable object = getRenderer().getValueFromFile(filename, PublisherSampler.DEFAULT_ENCODING, true, cache);
assertObject(object, "eéè€");
assertEquals("cache", format("%s%n", getUnicodeContent()), cacheContent.getValue());
}
@Test
public void getValueFromFile_withDefaultEncodingAndProlog() {
String filename = getResourceFile("object_prolog_cp1252.xml");
Serializable object = getRenderer().getValueFromFile(filename, PublisherSampler.DEFAULT_ENCODING, true, cache);
assertObject(object, "eéè€");
Person p = (Person) object;
assertEquals("object.name", "eéè€", p.getName());
assertEquals("cache", format("<?xml version=\"1.0\" encoding=\"Windows-1252\"?>%n%s%n", getUnicodeContent()), cacheContent.getValue());
}
private String getUnicodeContent() {
return "<org.apache.jmeter.protocol.jms.sampler.render.Person><name>eéè€</name></org.apache.jmeter.protocol.jms.sampler.render.Person>";
}
private String getDoeContent() {
return "<org.apache.jmeter.protocol.jms.sampler.render.Person><name>Doe</name></org.apache.jmeter.protocol.jms.sampler.render.Person>";
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.protocol.jms.sampler.render;
import java.io.Serializable;
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,94 @@
/*
* 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.protocol.jms.sampler.render;
import static java.lang.String.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import java.util.Arrays;
import org.junit.Test;
/**
*
*/
public class TextMessageRendererTest extends MessageRendererTest<String> {
private TextMessageRenderer render = RendererFactory.getInstance().getText();
@Override
protected MessageRenderer<String> getRenderer() {
return render;
}
@Test
public void readUTF8File() {
assertContent("utf8.txt", "UTF-8");
}
@Test
public void readCP1252File() {
assertContent("cp1252.txt", "Cp1252");
}
private void assertContent(String resource, String encoding) {
String filename = getResourceFile(resource);
String actual = render.getContent(new FileKey(filename, encoding));
assertEquals(format("éè€%n"), actual);
}
@Test
public void getValueFromFileWithNoVar() {
assertValueFromFile(format("noVar%n"), "noVar.txt", true);
}
@Test
public void getValueFromFileWithOneVar() {
jmeterCtxService.get().getVariables().put("oneVar", "foobar");
assertValueFromFile(format("foobar%n"), "oneVar.txt", true);
}
@Test
public void checkCache() {
jmeterCtxService.get().getVariables().put("oneVar", "foo");
assertValueFromFile(format("foo%n"), "oneVar.txt", true);
assertEquals(format("${oneVar}%n"), cacheContent.getValue());
jmeterCtxService.get().getVariables().put("oneVar", "bar");
assertValueFromFile(format("bar%n"), "oneVar.txt", true);
assertEquals(format("${oneVar}%n"), cacheContent.getValue());
}
@Test
public void checkNoVariable() {
jmeterCtxService.get().getVariables().put("oneVar", "RAW");
assertValueFromFile(format("${oneVar}%n"), "oneVar.txt", false);
}
@Test
public void getValueFromText() {
for (String text : Arrays.asList("a", null, "b", "")) {
assertSame(text, render.getValueFromText(text));
}
}
protected void assertValueFromFile(String expected, String resource, boolean hasVariable) {
assertValueFromFile(actual -> assertEquals(expected, actual), resource, hasVariable);
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.test;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
public interface ResourceLocator {
public static String getResource(Object instance, String path) {
return getResource(instance.getClass(), path);
}
public static String getResource(Class<?> basetype, String path) {
Path nioPath = getResourcePath(basetype, path);
return nioPath.toString();
}
public static Path getResourcePath(Object instance, String path) {
return getResourcePath(instance.getClass(), path);
}
public static Path getResourcePath(Class<?> basetype, String path) {
URL url = basetype.getResource(path);
if (url == null) return null;
Path nioPath;
try {
nioPath = Paths.get(url.toURI());
} catch (URISyntaxException e) {
throw new IllegalStateException(e);
}
return nioPath;
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.threads;
import org.junit.rules.ExternalResource;
public class JMeterContextServiceHelper extends ExternalResource {
@Override
protected void after() {
JMeterContextService.removeContext();
}
private JMeterContext instance;
public JMeterContext get() {
if (instance == null) {
JMeterContext jMeterContext = new JMeterContext();
JMeterContextService.replaceContext(jMeterContext);
initContext(jMeterContext);
instance = jMeterContext;
}
return instance;
}
protected void initContext(JMeterContext jMeterContext) {}
}

View File

@ -140,6 +140,7 @@ JMeter now requires Java 8. Ensure you use most up to date version.
<h3>Other samplers</h3>
<ul>
<li><pr>241</pr>Support variable for all JMS messages (bytes, object, ...) and sources (file, folder)</li>
<li><bug>60585</bug>JMS Publisher and JMS Subscriber : Allow reconnection on error and pause between errors. Based on <pr>240</pr> from by Logan Mauzaize (logan.mauzaize at gmail.com) and Maxime Chassagneux (maxime.chassagneux at gmail.com).</li>
<li><pr>259</pr>Refactored and reformatted SmtpSampler. Contributed by Graham Russell (graham at ham1.co.uk)</li>
</ul>