001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.requestreply;
022
023 import junit.framework.Assert;
024 import junit.framework.Test;
025 import junit.framework.TestSuite;
026
027 import org.apache.log4j.Logger;
028
029 import org.apache.qpid.junit.extensions.AsymptoticTestCase;
030 import org.apache.qpid.junit.extensions.util.ParsedProperties;
031 import org.apache.qpid.junit.extensions.util.TestContextProperties;
032
033 import javax.jms.*;
034
035 /**
036 * PingPongTestPerf is a full round trip ping test, that has been written with the intention of being scaled up to run
037 * many times simultaneously to simluate many clients/producer/connections. A full round trip ping sends a message from
038 * a producer to a conumer, then the consumer replies to the message on a temporary queue.
039 *
040 * <p/>A single run of the test using the default JUnit test runner will result in the sending and timing of the number
041 * of pings specified by the test size and time how long it takes for all of these to complete. This test may be scaled
042 * up using a suitable JUnit test runner. See {@link org.apache.qpid.junit.extensions.TKTestRunner} for more
043 * information on how to do this.
044 *
045 * <p/>The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a
046 * temporary queue for replies. This setup is only established once for all the test repeats, but each test threads
047 * gets its own connection/producer/consumer, this is only re-established if the connection is lost.
048 *
049 * <p/>The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that
050 * is the name of the temporary queue, fires off many messages on the original queue and waits for them all to come
051 * back on the temporary queue.
052 *
053 * <p/>Configurable test properties: message size, transacted or not, persistent or not. Broker connection details.
054 *
055 * <p><table id="crc"><caption>CRC Card</caption>
056 * <tr><th> Responsibilities <th> Collaborations
057 * </table>
058 */
059 public class PingPongTestPerf extends AsymptoticTestCase
060 {
061 private static Logger _logger = Logger.getLogger(PingPongTestPerf.class);
062
063 /** Thread local to hold the per-thread test setup fields. */
064 ThreadLocal<PerThreadSetup> threadSetup = new ThreadLocal<PerThreadSetup>();
065
066 // Set up a property reader to extract the test parameters from. Once ContextualProperties is available in
067 // the project dependencies, use it to get property overrides for configurable tests and to notify the test runner
068 // of the test parameters to log with the results. It also providers some basic type parsing convenience methods.
069 // private Properties testParameters = System.getProperties();
070 private ParsedProperties testParameters =
071 TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/);
072
073 public PingPongTestPerf(String name)
074 {
075 super(name);
076
077 _logger.debug(testParameters);
078
079 // Sets up the test parameters with defaults.
080 /*testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME,
081 Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT));
082 testParameters.setPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME,
083 Integer.toString(PingPongProducer.MESSAGE_SIZE_DEAFULT));
084 testParameters.setPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME,
085 PingPongProducer.PING_QUEUE_NAME_DEFAULT);
086 testParameters.setPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME,
087 Boolean.toString(PingPongProducer.PERSISTENT_MODE_DEFAULT));
088 testParameters.setPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME,
089 Boolean.toString(PingPongProducer.TRANSACTED_DEFAULT));
090 testParameters.setPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.BROKER_DEFAULT);
091 testParameters.setPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.USERNAME_DEFAULT);
092 testParameters.setPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.PASSWORD_DEFAULT);
093 testParameters.setPropertyIfNull(PingPongProducer.VIRTUAL_HOST_PROPNAME, PingPongProducer.VIRTUAL_HOST_DEFAULT);
094 testParameters.setPropertyIfNull(PingPongProducer.VERBOSE_PROPNAME,
095 Boolean.toString(PingPongProducer.VERBOSE_DEFAULT));
096 testParameters.setPropertyIfNull(PingPongProducer.RATE_PROPNAME, Integer.toString(PingPongProducer.RATE_DEFAULT));
097 testParameters.setPropertyIfNull(PingPongProducer.PUBSUB_PROPNAME,
098 Boolean.toString(PingPongProducer.PUBSUB_DEFAULT));
099 testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME,
100 Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT));
101 testParameters.setPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME, Long.toString(PingPongProducer.TIMEOUT_DEFAULT));
102 testParameters.setPropertyIfNull(PingPongProducer.DESTINATION_COUNT_PROPNAME,
103 Integer.toString(PingPongProducer.DESTINATION_COUNT_DEFAULT));
104 testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME,
105 PingPongProducer.FAIL_AFTER_COMMIT_DEFAULT);
106 testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME,
107 PingPongProducer.FAIL_BEFORE_COMMIT_DEFAULT);
108 testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME,
109 PingPongProducer.FAIL_AFTER_SEND_DEFAULT);
110 testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME,
111 PingPongProducer.FAIL_BEFORE_SEND_DEFAULT);
112 testParameters.setPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.FAIL_ONCE_DEFAULT);
113 testParameters.setPropertyIfNull(PingPongProducer.UNIQUE_DESTS_PROPNAME,
114 Boolean.toString(PingPongProducer.UNIQUE_DESTS_DEFAULT));
115 testParameters.setPropertyIfNull(PingPongProducer.ACK_MODE_PROPNAME,
116 Integer.toString(PingPongProducer.ACK_MODE_DEFAULT));
117 testParameters.setPropertyIfNull(PingPongProducer.PAUSE_AFTER_BATCH_PROPNAME,
118 PingPongProducer.PAUSE_AFTER_BATCH_DEFAULT);*/
119 }
120
121 /**
122 * Compile all the tests into a test suite.
123 */
124 public static Test suite()
125 {
126 // Build a new test suite
127 TestSuite suite = new TestSuite("Ping-Pong Performance Tests");
128
129 // Run performance tests in read committed mode.
130 suite.addTest(new PingPongTestPerf("testPingPongOk"));
131
132 return suite;
133 }
134
135 private static void setSystemPropertyIfNull(String propName, String propValue)
136 {
137 if (System.getProperty(propName) == null)
138 {
139 System.setProperty(propName, propValue);
140 }
141 }
142
143 public void testPingPongOk(int numPings) throws Exception
144 {
145 // Get the per thread test setup to run the test through.
146 PerThreadSetup perThreadSetup = threadSetup.get();
147
148 // Generate a sample message. This message is already time stamped and has its reply-to destination set.
149 Message msg =
150 perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestinations().get(0),
151 testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME),
152 testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME));
153
154 // Send the message and wait for a reply.
155 int numReplies =
156 perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, PingPongProducer.TIMEOUT_DEFAULT, null);
157
158 // Fail the test if the timeout was exceeded.
159 if (numReplies != numPings)
160 {
161 Assert.fail("The ping timed out, got " + numReplies + " out of " + numPings);
162 }
163 }
164
165 /**
166 * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
167 */
168 public void threadSetUp()
169 {
170 try
171 {
172 PerThreadSetup perThreadSetup = new PerThreadSetup();
173
174 // Extract the test set up paramaeters.
175 String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME);
176 String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME);
177 String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME);
178 String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_HOST_PROPNAME);
179 String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME);
180 boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME);
181 boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME);
182 String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME);
183 boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME);
184 boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.PUBSUB_PROPNAME);
185
186 synchronized (this)
187 {
188 // Establish a bounce back client on the ping queue to bounce back the pings.
189 perThreadSetup._testPingBouncer =
190 new PingPongBouncer(brokerDetails, username, password, virtualPath, destinationName, persistent,
191 transacted, selector, verbose, pubsub);
192
193 // Start the connections for client and producer running.
194 perThreadSetup._testPingBouncer.getConnection().start();
195
196 // Establish a ping-pong client on the ping queue to send the pings and receive replies with.
197 perThreadSetup._testPingProducer = new PingPongProducer(testParameters);
198 perThreadSetup._testPingProducer.establishConnection(true, true);
199 perThreadSetup._testPingProducer.start();
200 }
201
202 // Attach the per-thread set to the thread.
203 threadSetup.set(perThreadSetup);
204 }
205 catch (Exception e)
206 {
207 _logger.warn("There was an exception during per thread setup.", e);
208 }
209 }
210
211 /**
212 * Performs test fixture clean
213 */
214 public void threadTearDown()
215 {
216 _logger.debug("public void threadTearDown(): called");
217
218 try
219 {
220 // Get the per thread test fixture.
221 PerThreadSetup perThreadSetup = threadSetup.get();
222
223 // Close the pingers so that it cleans up its connection cleanly.
224 synchronized (this)
225 {
226 perThreadSetup._testPingProducer.close();
227 // perThreadSetup._testPingBouncer.close();
228 }
229
230 // Ensure the per thread fixture is reclaimed.
231 threadSetup.remove();
232 }
233 catch (JMSException e)
234 {
235 _logger.warn("There was an exception during per thread tear down.");
236 }
237 }
238
239 protected static class PerThreadSetup
240 {
241 /**
242 * Holds the test ping-pong producer.
243 */
244 private PingPongProducer _testPingProducer;
245
246 /**
247 * Holds the test ping client.
248 */
249 private PingPongBouncer _testPingBouncer;
250 }
251 }
|