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.ping;
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.requestreply.PingPongProducer;
030
031 import org.apache.qpid.junit.extensions.AsymptoticTestCase;
032 import org.apache.qpid.junit.extensions.TestThreadAware;
033 import org.apache.qpid.junit.extensions.util.ParsedProperties;
034 import org.apache.qpid.junit.extensions.util.TestContextProperties;
035
036 import javax.jms.*;
037
038 /**
039 * PingTestPerf is a ping test, that has been written with the intention of being scaled up to run many times
040 * simultaneously to simluate many clients/producers/connections.
041 *
042 * <p/>A single run of the test using the default JUnit test runner will result in the sending and timing of a single
043 * full round trip ping. This test may be scaled up using a suitable JUnit test runner.
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/threads that may be run,
047 * except if the connection is lost in which case an attempt to re-establish the setup is made.
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 a message on the original queue and waits for a response on the
051 * 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 PingTestPerf extends AsymptoticTestCase implements TestThreadAware
060 {
061 private static Logger _logger = Logger.getLogger(PingTestPerf.class);
062
063 /** Thread local to hold the per-thread test setup fields. */
064 ThreadLocal<PerThreadSetup> threadSetup = new ThreadLocal<PerThreadSetup>();
065
066 /** Holds a property reader to extract the test parameters from. */
067 protected ParsedProperties testParameters =
068 TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/);
069
070 public PingTestPerf(String name)
071 {
072 super(name);
073
074 _logger.debug("testParameters = " + testParameters);
075 }
076
077 /**
078 * Compile all the tests into a test suite.
079 * @return The test method testPingOk.
080 */
081 public static Test suite()
082 {
083 // Build a new test suite
084 TestSuite suite = new TestSuite("Ping Performance Tests");
085
086 // Run performance tests in read committed mode.
087 suite.addTest(new PingTestPerf("testPingOk"));
088
089 return suite;
090 }
091
092 public void testPingOk(int numPings) throws Exception
093 {
094 if (numPings == 0)
095 {
096 Assert.fail("Number of pings requested was zero.");
097 }
098
099 // Get the per thread test setup to run the test through.
100 PerThreadSetup perThreadSetup = threadSetup.get();
101
102 if (perThreadSetup == null)
103 {
104 Assert.fail("Could not get per thread test setup, it was null.");
105 }
106
107 // Generate a sample message. This message is already time stamped and has its reply-to destination set.
108 Message msg =
109 perThreadSetup._pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0),
110 testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME),
111 testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME));
112
113 // start the test
114 long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME));
115 int numReplies = perThreadSetup._pingClient.pingAndWaitForReply(msg, numPings, timeout, null);
116
117 // Fail the test if the timeout was exceeded.
118 if (numReplies != perThreadSetup._pingClient.getExpectedNumPings(numPings))
119 {
120 Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = "
121 + numReplies);
122 }
123 }
124
125 /**
126 * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
127 */
128 public void threadSetUp()
129 {
130 _logger.debug("public void threadSetUp(): called");
131
132 try
133 {
134 PerThreadSetup perThreadSetup = new PerThreadSetup();
135
136 // This is synchronized because there is a race condition, which causes one connection to sleep if
137 // all threads try to create connection concurrently.
138 synchronized (this)
139 {
140 // Establish a client to ping a Destination and listen the reply back from same Destination
141 perThreadSetup._pingClient = new PingClient(testParameters);
142 perThreadSetup._pingClient.establishConnection(true, true);
143 }
144 // Start the client connection
145 perThreadSetup._pingClient.start();
146
147 // Attach the per-thread set to the thread.
148 threadSetup.set(perThreadSetup);
149 }
150 catch (Exception e)
151 {
152 _logger.warn("There was an exception during per thread setup.", e);
153 }
154 }
155
156 /**
157 * Performs test fixture clean
158 */
159 public void threadTearDown()
160 {
161 _logger.debug("public void threadTearDown(): called");
162
163 try
164 {
165 // Get the per thread test fixture.
166 PerThreadSetup perThreadSetup = threadSetup.get();
167
168 // Close the pingers so that it cleans up its connection cleanly.
169 synchronized (this)
170 {
171 if ((perThreadSetup != null) && (perThreadSetup._pingClient != null))
172 {
173 perThreadSetup._pingClient.close();
174 }
175 }
176 }
177 catch (JMSException e)
178 {
179 _logger.warn("There was an exception during per thread tear down.");
180 }
181 finally
182 {
183 // Ensure the per thread fixture is reclaimed.
184 threadSetup.remove();
185 }
186 }
187
188 protected static class PerThreadSetup
189 {
190 /**
191 * Holds the test ping client.
192 */
193 protected PingClient _pingClient;
194 protected String _correlationId;
195 }
196 }
|