Author: pmouawad Date: Tue Nov 28 21:06:45 2017 New Revision: 1816573 URL: http://svn.apache.org/viewvc?rev=1816573&view=rev Log: Bug 61829 - JMS Point-to-Point : If Receive Queue is empty and a timeout is set, it is not taken into account Fixes also timeout == 0 is reset to 2s Bugzilla Id: 61829
Added: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TimeoutEnabledQueueRequestor.java (with props) Modified: jmeter/trunk/bin/testfiles/JMS_TESTS.csv jmeter/trunk/bin/testfiles/JMS_TESTS.jmx jmeter/trunk/bin/testfiles/JMS_TESTS.xml jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/FixedQueueExecutor.java jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/QueueExecutor.java jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TemporaryQueueExecutor.java jmeter/trunk/xdocs/changes.xml Modified: jmeter/trunk/bin/testfiles/JMS_TESTS.csv URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/testfiles/JMS_TESTS.csv?rev=1816573&r1=1816572&r2=1816573&view=diff ============================================================================== --- jmeter/trunk/bin/testfiles/JMS_TESTS.csv (original) +++ jmeter/trunk/bin/testfiles/JMS_TESTS.csv Tue Nov 28 21:06:45 2017 @@ -14,6 +14,7 @@ JMS-P2P-Read,200,1 message(s) received s JMS-P2P-RequestOnlyForClear,200,OK,TG-JMS-P2P 1-1,text,true,1,1,1,0 JMS-P2P-Clear,200,1 message(s) removed using receive timeout:100ms,TG-JMS-P2P 1-1,text,true,1,1,1,0 JMS-P2P-BrowseAfterClear,200,0 messages available on the queue,TG-JMS-P2P 1-1,text,true,1,1,1,0 +JMS-P2P-Timeout,,No reply message received,TG-JMS-P2P 1-1,text,true,1,1,1,0 JMS Publisher-NonDurable,200,1 messages published,TG-JMS-PS 2-1,,true,1,1,1,0 JMS Subscriber-NonDurable,200,1 message(s) received successfully of 1 expected,TG-JMS-PS 2-1,text,true,1,1,1,0 JMS Publisher-Persistent,200,1 messages published,TG-JMS-PS-Selector-receive 3-1,,true,1,1,1,0 Modified: jmeter/trunk/bin/testfiles/JMS_TESTS.jmx URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/testfiles/JMS_TESTS.jmx?rev=1816573&r1=1816572&r2=1816573&view=diff ============================================================================== --- jmeter/trunk/bin/testfiles/JMS_TESTS.jmx (original) +++ jmeter/trunk/bin/testfiles/JMS_TESTS.jmx Tue Nov 28 21:06:45 2017 @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<jmeterTestPlan version="1.2" properties="3.4" jmeter="3.4-SNAPSHOT.20171119"> +<jmeterTestPlan version="1.2" properties="3.4" jmeter="4.0-SNAPSHOT.20171128"> <hashTree> <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true"> <stringProp name="TestPlan.comments"></stringProp> @@ -663,6 +663,37 @@ finally { <intProp name="Assertion.test_type">16</intProp> </ResponseAssertion> <hashTree/> + </hashTree> + <JMSSampler guiclass="JMSSamplerGui" testclass="JMSSampler" testname="JMS-P2P-Timeout" enabled="true"> + <stringProp name="JMSSampler.queueconnectionfactory">ConnectionFactory</stringProp> + <stringProp name="JMSSampler.SendQueue">dynamicQueues/requestQueue7</stringProp> + <stringProp name="JMSSampler.ReceiveQueue"></stringProp> + <intProp name="JMSSampler.communicationStyle">1</intProp> + <boolProp name="JMSSampler.isNonPersistent">false</boolProp> + <boolProp name="JMSSampler.useReqMsgIdAsCorrelId">true</boolProp> + <stringProp name="JMSSampler.timeout">2000</stringProp> + <stringProp name="JMSSampler.jmsNumberOfSamplesToAggregate"></stringProp> + <stringProp name="HTTPSamper.xml_data">test</stringProp> + <stringProp name="JMSSampler.initialContextFactory">org.apache.activemq.jndi.ActiveMQInitialContextFactory</stringProp> + <stringProp name="JMSSampler.contextProviderUrl">tcp://localhost:61616</stringProp> + <elementProp name="JMSSampler.jndiProperties" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> + <collectionProp name="Arguments.arguments"/> + </elementProp> + <elementProp name="arguments" elementType="JMSProperties"> + <collectionProp name="JMSProperties.properties"/> + </elementProp> + <boolProp name="JMSSampler.useResMsgIdAsCorrelId">true</boolProp> + </JMSSampler> + <hashTree> + <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="RA_noMessage" enabled="true"> + <collectionProp name="Asserion.test_strings"> + <stringProp name="1882001775">No reply message received</stringProp> + </collectionProp> + <stringProp name="Assertion.test_field">Assertion.response_message</stringProp> + <boolProp name="Assertion.assume_success">true</boolProp> + <intProp name="Assertion.test_type">16</intProp> + </ResponseAssertion> + <hashTree/> </hashTree> </hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="TG-JMS-PS" enabled="true"> Modified: jmeter/trunk/bin/testfiles/JMS_TESTS.xml URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/testfiles/JMS_TESTS.xml?rev=1816573&r1=1816572&r2=1816573&view=diff ============================================================================== --- jmeter/trunk/bin/testfiles/JMS_TESTS.xml (original) +++ jmeter/trunk/bin/testfiles/JMS_TESTS.xml Tue Nov 28 21:06:45 2017 @@ -99,6 +99,13 @@ <error>false</error> </assertionResult> </sample> +<sample s="true" lb="JMS-P2P-Timeout" rc="" rm="No reply message received" tn="TG-JMS-P2P 1-1" dt="text" sc="1" ec="0" ng="1" na="1"> + <assertionResult> + <name>RA_noMessage</name> + <failure>false</failure> + <error>false</error> + </assertionResult> +</sample> <sample s="true" lb="JMS Publisher-NonDurable" rc="200" rm="1 messages published" tn="TG-JMS-PS 2-1" dt="" sc="1" ec="0" ng="1" na="1"> <assertionResult> <name>Response Assertion</name> Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/FixedQueueExecutor.java URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/FixedQueueExecutor.java?rev=1816573&r1=1816572&r2=1816573&view=diff ============================================================================== --- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/FixedQueueExecutor.java (original) +++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/FixedQueueExecutor.java Tue Nov 28 21:06:45 2017 @@ -95,10 +95,11 @@ public class FixedQueueExecutor implemen // This used to be request.wait(timeout_ms), where 0 means forever // However 0 means return immediately for the latch if (timeout == 0){ + log.debug("Waiting infinitely for message"); countDownLatch.await(); // } else { if(!countDownLatch.await(timeout, TimeUnit.MILLISECONDS)) { - log.debug("Timeout reached before getting a reply message"); + log.debug("Timeout {} ms reached before getting a reply message", timeout); } } log.debug("{} done waiting for {} on {} ended on {}", @@ -110,4 +111,9 @@ public class FixedQueueExecutor implemen } return admin.get(id); } + + @Override + public void close() throws JMSException { + // NOOP + } } Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java?rev=1816573&r1=1816572&r2=1816573&view=diff ============================================================================== --- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java (original) +++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java Tue Nov 28 21:06:45 2017 @@ -43,6 +43,7 @@ import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; +import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.config.Arguments; import org.apache.jmeter.protocol.jms.Utils; import org.apache.jmeter.samplers.AbstractSampler; @@ -678,7 +679,7 @@ public class JMSSampler extends Abstract producer.setTimeToLive(Long.parseLong(getExpiration())); } else { if (useTemporyQueue()) { - executor = new TemporaryQueueExecutor(session, sendQueue); + executor = new TemporaryQueueExecutor(session, sendQueue, getTimeoutAsInt()); } else { producer = session.createSender(sendQueue); executor = new FixedQueueExecutor(producer, getTimeoutAsInt(), isUseReqMsgIdAsCorrelId()); @@ -755,10 +756,12 @@ public class JMSSampler extends Abstract } private int getTimeoutAsInt() { - if (getPropertyAsInt(TIMEOUT) < 1) { + String propAsString = getPropertyAsString(TIMEOUT); + if(StringUtils.isEmpty(propAsString)){ return DEFAULT_TIMEOUT; + } else { + return Integer.parseInt(propAsString); } - return getPropertyAsInt(TIMEOUT); } public String getTimeout() { @@ -797,6 +800,13 @@ public class JMSSampler extends Abstract // ignore } } + if (executor != null) { + try { + executor.close(); + } catch (JMSException e) { + LOGGER.error("Error closing executor {}", executor.getClass(), e); + } + } Utils.close(session, LOGGER); Utils.close(connection, LOGGER); if (receiverThread != null) { Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/QueueExecutor.java URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/QueueExecutor.java?rev=1816573&r1=1816572&r2=1816573&view=diff ============================================================================== --- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/QueueExecutor.java (original) +++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/QueueExecutor.java Tue Nov 28 21:06:45 2017 @@ -18,12 +18,13 @@ package org.apache.jmeter.protocol.jms.sampler; +import java.io.Closeable; + import javax.jms.JMSException; import javax.jms.Message; /** * Executor for (pseudo) synchronous communication. <br> - * Created on: October 28, 2004 * */ public interface QueueExecutor { @@ -43,4 +44,9 @@ public interface QueueExecutor { int priority, long expiration) throws JMSException; + /** + * Close the resources + * @throws JMSException + */ + void close() throws JMSException; } Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TemporaryQueueExecutor.java URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TemporaryQueueExecutor.java?rev=1816573&r1=1816572&r2=1816573&view=diff ============================================================================== --- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TemporaryQueueExecutor.java (original) +++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TemporaryQueueExecutor.java Tue Nov 28 21:06:45 2017 @@ -24,14 +24,19 @@ import javax.jms.Queue; import javax.jms.QueueRequestor; import javax.jms.QueueSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Request/reply executor with a temporary reply queue. <br> * * Used by JMS Sampler (Point to Point) */ public class TemporaryQueueExecutor implements QueueExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(TemporaryQueueExecutor.class); /** The sender and receiver. */ - private final QueueRequestor requestor; + private final TimeoutEnabledQueueRequestor requestor; + private int timeout; /** * Constructor. @@ -40,13 +45,15 @@ public class TemporaryQueueExecutor impl * the session to use to send the message * @param destination * the queue to send the message on + * @param timeoutMs Timeout in millis * @throws JMSException * when internally used {@link QueueRequestor} can not be * constructed with <code>session</code> and * <code>destination</code> */ - public TemporaryQueueExecutor(QueueSession session, Queue destination) throws JMSException { - requestor = new QueueRequestor(session, destination); + public TemporaryQueueExecutor(QueueSession session, Queue destination, int timeoutMs) throws JMSException { + requestor = new TimeoutEnabledQueueRequestor(session, destination); + this.timeout = timeoutMs; } /** @@ -57,6 +64,13 @@ public class TemporaryQueueExecutor impl int deliveryMode, int priority, long expiration) throws JMSException { - return requestor.request(request); + LOGGER.debug("Sending message and waiting for response in Temporary queue with timeout {} ms (0==infinite)", + timeout); + return requestor.request(request, timeout); + } + + @Override + public void close() throws JMSException { + requestor.close(); } } Added: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TimeoutEnabledQueueRequestor.java URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TimeoutEnabledQueueRequestor.java?rev=1816573&view=auto ============================================================================== --- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TimeoutEnabledQueueRequestor.java (added) +++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TimeoutEnabledQueueRequestor.java Tue Nov 28 21:06:45 2017 @@ -0,0 +1,153 @@ +/* + * 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 javax.jms.InvalidDestinationException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TemporaryQueue; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The <code>TimeoutEnabledQueueRequestor</code> helper class simplifies making + * service requests using the request/reply pattern. + * + * <P> + * The <code>TimeoutEnabledQueueRequestor</code> constructor is given a + * non-transacted <code>QueueSession</code> and a destination + * <code>Queue</code>. It creates a <code>TemporaryQueue</code> for the + * responses and provides a <code>request</code> method that sends the request + * message and waits for its reply. + * + * @since 4.0 + */ +public class TimeoutEnabledQueueRequestor { + private static final Logger logger = LoggerFactory.getLogger(TimeoutEnabledQueueRequestor.class); + private Session session; // The queue session to which the queue belongs. + private TemporaryQueue tempQueue; + private MessageProducer sender; + private MessageConsumer receiver; + + /** + * Constructor for the <code>TimeoutEnabledQueueRequestor</code> class. + * + * <P> + * This implementation assumes the session parameter to be non-transacted, + * with a delivery mode of either <code>AUTO_ACKNOWLEDGE</code> or + * <code>DUPS_OK_ACKNOWLEDGE</code>. + * + * @paramsession the <code>QueueSession</code> the queue belongs to + * @paramqueue the queue to performthe request/reply call on + * + * @exception JMSException + * if the JMS provider fails to create the + * <code>TimeoutEnabledQueueRequestor</code> due to some + * internal error. + * @exception InvalidDestinationException + * if an invalid queue is specified. + */ + public TimeoutEnabledQueueRequestor(Session session, Queue queue) throws JMSException { + this.session = session; + tempQueue = session.createTemporaryQueue(); + sender = session.createProducer(queue); + receiver = session.createConsumer(tempQueue); + } + + /** + * Sends a request and waits for a reply. The temporary queue is used for + * the <code>JMSReplyTo</code> destination, and only one reply per request + * is expected. The method blocks indefinitely until a message arrives! + * + * @parammessage the message to send + * + * @return the reply message + * + * @exception JMSException + * if the JMS provider fails to complete the request due to + * some internal error. + */ + public Message request(Message message) throws JMSException { + return request(message, 0); + } + + /** + * Sends a request and waits for a reply. The temporary queue is used for + * the <code>JMSReplyTo</code> destination, and only one reply per request + * is expected. The client waits/blocks for the reply until the timeout is + * reached. + * + * @param message + * the message to send + * @param timeout + * time to wait for a reply on temporary queue. If you specify no + * arguments or an argument of 0, the method blocks indefinitely + * until a message arrives + * + * @return the reply message + * + * @exception JMSException + * if the JMS provider fails to complete the request due to + * some internal error. + */ + public Message request(Message message, long timeout) throws JMSException { + message.setJMSReplyTo(tempQueue); + sender.send(message); + return receiver.receive(timeout); + } + + /** + * Closes the <code>TimeoutEnabledQueueRequestor</code> and its session. + * + * <P> + * Since a provider may allocate some resources on behalf of a + * <code>TimeoutEnabledQueueRequestor</code> outside the Java virtual + * machine, clients should close them when they are not needed. Relying on + * garbage collection to eventually reclaim these resources may not be + * timely enough. + * + * <P> + * This method closes the <code>Session</code> object passed to the + * <code>TimeoutEnabledQueueRequestor</code> constructor. + * + * @exception JMSException + * if the JMS provider fails to close the + * <code>TimeoutEnabledQueueRequestor</code> due to some + * internal error. + */ + public void close() throws JMSException { + String queueName = tempQueue.getQueueName(); + try { + tempQueue.delete(); + } catch (Exception e) { + logger.error("Error deleting tempQueue {}", queueName); + } + // publisher and consumer created by constructor are implicitly closed. + try { + session.close(); + } catch (Exception e) { + logger.error("Error closing session", e); + } + } +} Propchange: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TimeoutEnabledQueueRequestor.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/TimeoutEnabledQueueRequestor.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: jmeter/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1816573&r1=1816572&r2=1816573&view=diff ============================================================================== --- jmeter/trunk/xdocs/changes.xml [utf-8] (original) +++ jmeter/trunk/xdocs/changes.xml [utf-8] Tue Nov 28 21:06:45 2017 @@ -85,6 +85,7 @@ Summary JMeter will move the <code>Mirror Server</code>, <code>Property Display</code> and HTTP(s) <code>Test Script Recorder</code> elements as direct children of Test Plan. For any other element, it will create a <code>Test Fragment</code> element called <code>Workbench Test Fragment and move the elements in it</code>.</li> <li>Following classes have been dropped (<code>org.apache.jmeter.functions.util.ArgumentEncoder</code>, <code>org.apache.jmeter.functions.util.ArgumentDecoder</code>), see <pr>335</pr></li> + <li>In JMS Point-to-Point sampler, setting timeout to 0 will now mean infinite timeout while previously it would be switched to 2000 ms, see <bugzilla>61829</bugzilla></li> </ul> <!-- =================== Improvements =================== --> @@ -104,6 +105,7 @@ Summary <li><bug>61739</bug>Java Request / JavaSamplerClient : Improve <code>org.apache.jmeter.protocol.java.sampler.JavaSamplerContext</code></li> <li><bug>61762</bug>Start Next Thread Loop should be used everywhere</li> <li><bug>61544</bug>JMS Point-to-Point Sampler: Enhance communication styles with read, browse, clear. Based on a contribution by Benny van Wijngaarden (benny at smaragd-it.nl)</li> + <li><bug>61829</bug>JMS Point-to-Point : If Receive Queue is empty and a timeout is set, it is not taken into account. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li> </ul> <h3>Controllers</h3>