--- src/components/org/apache/jmeter/timers/ThroughputInfo.java (revision 0)
+++ src/components/org/apache/jmeter/timers/ThroughputInfo.java (revision 0)
@@ -0,0 +1,103 @@
+/*
+ * 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.timers;
+
+import java.io.Serializable;
+
+/**
+ * Manages the throughput information in a thread safe way.
+ */
+public class ThroughputInfo implements Serializable {
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Extracted out for unit testing. See class javadoc.
+ */
+ private static SystemClock SYSTEM_CLOCK = new SystemClock();
+
+ /**
+ * Extracted out for unit testing. Java should optimize this away in
+ * production.
+ */
+ protected static class SystemClock {
+
+ /**
+ * @return System.currentTimeMillis
+ */
+ public long getCurrentTime() {
+ return System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Only used for unit testing to set a simulation clock instead of
+ * java.lang.System.
+ *
+ * @param systemClock
+ * the system clock to use
+ */
+ protected static void setSystemClock(SystemClock systemClock) {
+ SYSTEM_CLOCK = systemClock;
+ }
+
+ /**
+ * The time, in milliseconds, when the last scheduled event occurred.
+ *
+ * @GuardedBy("this")
+ */
+ private long lastScheduledTime = 0;
+
+ /**
+ *
+ * Calculate the delay needed to reach the target time of
+ * lastScheduledTime + delay
+ *
delay
+ * seconds after midnight, January 1, 1970 UTC)
+ */
+ long targetTime = lastScheduledTime + delay;
+ if (currentTime > targetTime) {
+ // We're behind schedule -- try to catch up:
+ lastScheduledTime = currentTime;
+ return 0;
+ }
+ lastScheduledTime = targetTime;
+ return targetTime - currentTime;
+
+ }
+
+ /**
+ * Reset the lastScheduledTime
to zero.
+ */
+ public synchronized void reset() {
+ lastScheduledTime = 0;
+ }
+
+}
--- src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java (revision 1140940)
+++ src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java (working copy)
@@ -18,7 +18,6 @@
package org.apache.jmeter.timers;
-import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.jmeter.engine.event.LoopIterationEvent;
@@ -37,25 +36,29 @@
* samples per unit of time approaches a given constant as much as possible.
*
* There are two different ways of pacing the requests:
- * - delay each thread according to when it last ran
- * - delay each thread according to when any thread last ran
+ * throughputInfo
if the mode is
+ * shared.
+ *
+ * @param mode
+ * the delay calculation mode
+ */
public void setCalcMode(String mode) {
this.calcMode = mode;
// TODO find better way to get modeInt
this.modeInt = ConstantThroughputTimerBeanInfo.getCalcModeAsInt(calcMode);
+
+ switch (modeInt) {
+ case CALC_MODE_4_ALL_ACTIVE_THREADS_SHARED:
+ throughputInfo = allThreadsInfo;
+ break;
+
+ case CALC_MODE_5_ALL_ACTIVE_THREADS_IN_CURRENT_THREAD_GROUP_SHARED:
+ final org.apache.jmeter.threads.AbstractThreadGroup group = JMeterContextService
+ .getContext().getThreadGroup();
+ /*
+ * Share the first thread's throughputInfo
+ */
+ threadGroupsInfoMap.putIfAbsent(group, throughputInfo);
+ throughputInfo = threadGroupsInfoMap.get(group);
+ break;
+ }
}
/**
@@ -121,89 +147,56 @@
* @see org.apache.jmeter.timers.Timer#delay()
*/
public long delay() {
- long currentTime = System.currentTimeMillis();
-
- /*
- * If previous time is zero, then target will be in the past.
- * This is what we want, so first sample is run without a delay.
- */
- long currentTarget = previousTime + calculateDelay();
- if (currentTime > currentTarget) {
- // We're behind schedule -- try to catch up:
- previousTime = currentTime;
- return 0;
- }
- previousTime = currentTarget;
- return currentTarget - currentTime;
+ return throughputInfo.calculateDelay(calculateDelayForMode());
}
/**
- * @param currentTime
- * @return new Target time
+ * + * Calculate the delay based on the mode + *
+ * + * @return the delay (how long before another request should be made) in + * milliseconds */ - // TODO - is this used? (apart from test code) - protected long calculateCurrentTarget(long currentTime) { - return currentTime + calculateDelay(); - } - - // Calculate the delay based on the mode - private long calculateDelay() { + private long calculateDelayForMode() { long delay = 0; // N.B. we fetch the throughput each time, as it may vary during a test double msPerRequest = (MILLISEC_PER_MIN / getThroughput()); switch (modeInt) { - case 1: // Total number of threads + case CALC_MODE_2_ALL_ACTIVE_THREADS: + /* + * Each request is allowed to run every msPerRequest. Each thread + * can run a request, so each thread needs to be delayed by the + * total pool size of threads to keep the expected throughput. + */ delay = (long) (JMeterContextService.getNumberOfThreads() * msPerRequest); break; - case 2: // Active threads in this group + case CALC_MODE_3_ALL_ACTIVE_THREADS_IN_CURRENT_THREAD_GROUP: + /* + * Each request is allowed to run every msPerRequest. Each thread + * can run a request, so each thread needs to be delayed by the + * total pool size of threads to keep the expected throughput. + */ delay = (long) (JMeterContextService.getContext().getThreadGroup().getNumberOfThreads() * msPerRequest); break; - case 3: // All threads - alternate calculation - delay = calculateSharedDelay(allThreadsInfo,(long) msPerRequest); + /* + * The following modes all fall through for the default + */ + case CALC_MODE_1_THIS_THREAD_ONLY: + case CALC_MODE_4_ALL_ACTIVE_THREADS_SHARED: + case CALC_MODE_5_ALL_ACTIVE_THREADS_IN_CURRENT_THREAD_GROUP_SHARED: + default: + delay = (long) msPerRequest; break; - - case 4: //All threads in this group - alternate calculation - final org.apache.jmeter.threads.AbstractThreadGroup group = - JMeterContextService.getContext().getThreadGroup(); - ThroughputInfo groupInfo; - synchronized (threadGroupsInfoMap) { - groupInfo = threadGroupsInfoMap.get(group); - if (groupInfo == null) { - groupInfo = new ThroughputInfo(); - threadGroupsInfoMap.put(group, groupInfo); - } - } - delay = calculateSharedDelay(groupInfo,(long) msPerRequest); - break; - - default: // e.g. 0 - delay = (long) msPerRequest; // i.e. * 1 - break; } return delay; } - private long calculateSharedDelay(ThroughputInfo info, long milliSecPerRequest) { - final long now = System.currentTimeMillis(); - final long calculatedDelay; - - //Synchronize on the info object's MUTEX to ensure - //Multiple threads don't update the scheduled time simultaneously - synchronized (info.MUTEX) { - final long nextRequstTime = info.lastScheduledTime + milliSecPerRequest; - info.lastScheduledTime = Math.max(now, nextRequstTime); - calculatedDelay = info.lastScheduledTime - now; - } - - return Math.max(calculatedDelay, 0); - } - private synchronized void reset() { - allThreadsInfo.lastScheduledTime = 0; - threadGroupsInfoMap.clear(); - previousTime = 0; + throughputInfo = new ThroughputInfo(); + setCalcMode(calcMode); } /** @@ -234,6 +227,14 @@ * {@inheritDoc} */ public void testEnded() { + /* + * There is no way to clean up static variables. The best place to do + * that is in the testEnded() call as this wont affect a running test. + * If these are in testStarted then they affect already initialised + * objects. + */ + allThreadsInfo.reset(); + threadGroupsInfoMap.clear(); } /** --- test/src/org/apache/jmeter/timers/ConstantThroughPutTimerSimulation.java (revision 0) +++ test/src/org/apache/jmeter/timers/ConstantThroughPutTimerSimulation.java (revision 0) @@ -0,0 +1,357 @@ +/* + * 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.timers; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; +import org.apache.jorphan.logging.LoggingManager; +import org.apache.log.Logger; + +/** + *+ * Builds {@link ConstantThroughputTimerTestData} from a simulation file. + *
+ *+ * See simulator_template.txt for an example file explaining the format + *
+ */ +public class ConstantThroughPutTimerSimulation { + + /** Logger */ + private static final Logger LOG = LoggingManager.getLoggerForClass(); + + /** + * The separator of the simulation file is comma + */ + private static final String SEPARATOR = ","; + + /** + * Regular expression pattern for the header + */ + private static final Pattern PATTERN_HEADER = Pattern + .compile("(\\d+)m(\\d)t(\\d+)\\[(\\d+)\\]"); + + /** + * Regular expression pattern for the columns + */ + private static final Pattern PATTERN_COLUMN = Pattern.compile("d=(\\d+)"); + + /** + * + * @param simulationFileName + * the file name of the simulation. Uses + * {@link ClassLoader#getResourceAsStream(String)} to find the + * file + * @return the InputStream containging the contents of the file + * @throws IOException + * failed to obtain file + */ + private InputStream getSimulationFile(String simulationFileName) + throws IOException { + return getClass().getClassLoader().getResourceAsStream( + simulationFileName); + } + + /** + * Load the specifiedsimulationFileName
(Using
+ * {@link ClassLoader#getResourceAsStream(String)}) and return a list of
+ * configured TestData representing the simulation.
+ *
+ * @param simulationFileName
+ * the file name of the simulation. Uses
+ * {@link ClassLoader#getResourceAsStream(String)} to find the
+ * file
+ * @return a list of configured TestData
+ * @throws IOException
+ * failed to obtain file
+ * @throws SimulationParseException
+ * failed to parse simulation file
+ */
+ public ListTestData
+ * @throws IOException
+ * failed to load the simulation file
+ * @throws SimulationParseException
+ * failed to parse simulation file
+ */
+ private ListTestData
+ * @param line
+ * the line to parse
+ * @throws SimulationParseException
+ * failed to parse simulation file
+ */
+ private void parseBody(ListmsPerRequest * ThreadsInThreadGroup Count
.
+# Timer 1 delay = 5000 * 1 = 5,000
+# Timer 2 delay = 3000 * 3 = 9,000
+# Timer 3 delay = 10000 * 5 = 50,000
+
+# delay = target time <= current time ? 0 : target time - simulation time
+# where target time = previous time + msPerRequest
+Simulation Time, 1m3t1[5000], 2m3t3[3000], 3m3t5[10000],
+ 0, d=0, d=0, d=0, # For non-shared Constant Throughput Timers the first request will be at time 0 with no delay.
+ 1000, d=4000, , , # timer 1 : target time = 0 + 5000 = 5000; delay = 5000 - 1000 = 4000
+ 4000, , d=5000, , # timer 2 : target time = 0 + 9000 = 9000; delay = 9000 - 4000 = 5000
+ 5000, X, , ,
+ 9000, , X, ,
+ 10000, X, , ,
+ 15000, X, , ,
+ 18000, , d=0, , # timer 2 : target time = 9000 + 9000 = 18000; delay = 0
+ 20000, X, , ,
+ 27000, , d=0, , # timer 2 : target time = 18000 + 9000 = 27000; delay = 0
+ 30000, , d=6000, , # timer 2 : target time = 27000 + 9000 = 36000; delay = 36000 - 30000 = 6000
+ 36000, , X, ,
+ 45000, X, , ,
+ 50000, X, , d=0, # timer 3 : target time = 0 + 50000 = 50000; delay = 0;
+ 70000, , , d=30000, # timer 3 : target time = 50000 + 50000 = 100000; delay = 100000 - 70000 = 30000
+ 100000, X, , X,
+ 150500, X, , X,
+ 150500, , , d=0, # timer 3 : target time = 10000 + 50000 = 150000; delay = 0
+ 200000, X, , X,
+
--- test/src/org/apache/jmeter/timers/ConstantThroughputTimerTestData.java (revision 0)
+++ test/src/org/apache/jmeter/timers/ConstantThroughputTimerTestData.java (revision 0)
@@ -0,0 +1,356 @@
+package org.apache.jmeter.timers;
+
+import static org.apache.jmeter.timers.Copy_Commons_Lang_2_5_Reflect.getDeclaredField;
+import static org.apache.jmeter.timers.Copy_Commons_Lang_2_5_Reflect.writeDeclaredStaticField;
+import static org.junit.Assert.assertEquals;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.ResourceBundle;
+
+import org.apache.jmeter.testbeans.BeanInfoSupport;
+import org.apache.jmeter.threads.AbstractThreadGroup;
+import org.apache.jmeter.threads.JMeterContext;
+import org.apache.jmeter.threads.JMeterContextService;
+import org.apache.jmeter.threads.MockJMeterContext;
+
+/**
+ * Data class for bundling test data around.
+ */
+public class ConstantThroughputTimerTestData {
+ private static ConstantThroughputTimerBeanInfo BEAN_INFO = new ConstantThroughputTimerBeanInfo();
+
+ /**
+ * this thread only
+ */
+ public static final String CALC_MODE_1 = "calcMode.1";
+
+ /**
+ * all active threads
+ */
+ public static final String CALC_MODE_2 = "calcMode.2";
+
+ /**
+ * all active threads in current thread group
+ */
+ public static final String CALC_MODE_3 = "calcMode.3";
+
+ /**
+ * all active threads (shared)
+ */
+ public static final String CALC_MODE_4 = "calcMode.4";
+
+ /**
+ * all active threads in current thread group (shared)
+ */
+ public static final String CALC_MODE_5 = "calcMode.5";
+
+ /**
+ * Mock JMeterContext which requires a delegate to the actual context.
+ * Actual contexts are in ConstantThroughputTimerTestData
+ */
+ private static MockJMeterContext mockJMeterContext = new MockJMeterContext();
+
+ private static ResourceBundle RESOURCE_BUNDLE = (ResourceBundle) BEAN_INFO
+ .getBeanDescriptor().getValue(BeanInfoSupport.RESOURCE_BUNDLE);
+
+ public static final String RESOURCE_BUNDLE_KEY_CALC_MODE_PREFIX = "calcMode.";
+
+ /**
+ * Go through the test data list and create additional TestData
+ * instances for each thread in the thread groups.
+ *
+ * @param testDataList
+ * the test data list
+ */
+ public static void createAdditionalThreads(
+ ListJMeterContextService.numberOfActiveThreads
based on
+ * the test data list provided.
+ *
+ * @param testDataList
+ * the test data list
+ * @throws IllegalAccessException
+ * failed to setup
+ * JMeterContextService.numberOfActiveThreads
+ */
+ public static void setupJMeterContextService_numberOfActiveThreads(
+ List+ * Create a copy of the specified instance. + *
+ *+ * Some properties will be shared from the instance: + *
threadGroup
+ * events
, only if the calcMode
is one of the
+ * shared modes.
+ *
+ * Uses the JMeter numberOfThreads
(i.e. active threads in the
+ * thread group) not the property NumThreads
, which is on the
+ * test plan.
+ *
numberOfThreadsInThreadGroup
+ */
+ private Collectionactivate
this Test Data.
+ *
+ * @param mode
+ * the mode to set
+ */
+ public void setCalcMode(String mode) {
+ activate();
+ this.calcMode = mode;
+ String modeStringFromResourceBundle = RESOURCE_BUNDLE.getString(mode);
+ timer.setCalcMode(modeStringFromResourceBundle);
+ }
+
+ /**
+ *
+ * Note: Will also set throughput
and update the
+ * timer
+ *
+ * Sets the JMeter numberOfThreads
(i.e. active threads in the
+ * thread group) not the property NumThreads
, which is on the
+ * test plan.
+ *
+ * Note: Will also set msPerRequest
and update the
+ * timer
.
+ *
msPerRequest
.
+# The difference with the simulator in calc mode "all active threads (shared mode)"
+# is that each thread group will share a single event stream instead of getting a copy of the event stream.
+# For "all active threads (shared mode)" each timer uses its own delay,
+# but the calculation is based on when the last thread was run at.
+# This makes the simulation file trickier to read since all columns need to be considered when calculating the expected delay.
+# If multiple columns all have values at the same simulation time, then the simulator runs them left to right
+# Optimal boundaries are not marked as its too complicated - each thread has their own optimal value based on the thread's start time.
+# It also gets confusing because threads can request a new start time any time before the actual thread start time needed.
+# Generally, if you are going to use this mode then all timers would use the same msPerRequest.
+Simulation Time, 1m4t1[5000], 2m4t3[3000], 3m4t5[10000],
+ 0, d=0, d=3000, d=13000, # For "all active threads (shared mode)" Constant Throughput Timers only the first thread to make the request will be at time 0 with no delay.
+ 1000, , , , # Subsequent Threads delays are calculated based on the previous time and each thread group shares the event stream.
+ 2000, , , , # delay = target time <= current time ? 0 : target time - simulation time
+ 3000, , , , # where target time = previous time + msPerRequest
+ 4000, , , , # timer 2 : target time = 0 + 3000 = 3000; delay = 3000 - 0 = 3000
+ 5000, , , , # timer 3 : target time = 3000 + 10000 = 130000; delay = 13000 - 0 = 13000
+ 6000, , , ,
+ 7000, , , d=16000, # timer 3 : target time = 13000 + 10000 = 23000; delay = 23000 - 7000 = 16000
+ 8000, , , ,
+ 9000, d=19000, , , # timer 1 : target time = 23000 + 5000 = 28000; delay = 28000 - 9000 = 19000
+ 10000, , , ,
+ 11000, , , ,
+ 12000, , , ,
+ 13000, , , , # 3rd thread start time
+ 14000, , , ,
+ 15000, , , ,
+ 16000, , , ,
+ 17000, , , ,
+ 18000, , , ,
+ 19000, , , ,
+ 20000, , , ,
+ 21000, , , ,
+ 22000, , , ,
+ 23000, , , , # 4th thread start time
+ 24000, , , ,
+ 25000, , , ,
+ 26000, , , ,
+ 27000, , , ,
+ 28000, , , , # 5th thread start time
+ 29000, , , ,
+ 30000, , , ,
+ 31000, , , ,
+ 32000, , , ,
+ 33000, , d=0, , # 6th thread start time, timer 2 : target time = 28000 + 5000 = 33000; delay = 0
+ 34000, , d=2000, , # timer 2 : target time = 33000 + 3000 = 36000; delay = 36000 - 34000 = 2000
+ 35000, , , ,
+ 36000, , , , # 7th thread start time
+ 37000, , , ,
+ 38000, , , d=8000, # timer 3 : target time = 36000 + 10000 = 46000; delay = 46000 - 38000 = 8000
+ 39000, , , ,
+ 40000, , , ,
+ 41000, , , ,
+ 42000, , , ,
+ 43000, , , ,
+ 44000, , , ,
+ 45000, , , ,
+ 46000, , , , # 8th thread start time
+ 47000, , , ,
+ 48000, , , ,
+ 49000, , , ,
+ 50000, , , ,
+ 50999, d=1, , , # timer 1 : target time = 46000 + 5000 = 51000; delay = 51000 - 50999 = 1
+ 51000, , , , # 9th thread start time
+ 52000, , , ,
+ 53000, , , ,
+ 54000, , , ,
+ 55000, , , ,
+ 56000, , , ,
+ 57000, , , ,
+ 58000, , , ,
+ 59000, , , ,
+ 60000, , , ,
+ 61000, , , ,
+ 61001, , , d=0, # timer 3 : target time = 51000 + 10000 = 61000; delay = 0
--- test/src/org/apache/jmeter/timers/PackageTest.java (revision 1140940)
+++ test/src/org/apache/jmeter/timers/PackageTest.java (working copy)
@@ -32,18 +32,34 @@
private static final Logger log = LoggingManager.getLoggerForClass();
+ private SimulationClock simulationClock = new SimulationClock();
+
public PackageTest(String arg0) {
super(arg0);
}
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ ThroughputInfo.setSystemClock(simulationClock);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ThroughputInfo.setSystemClock(new ThroughputInfo.SystemClock());
+ super.tearDown();
+ }
+
public void testTimer1() throws Exception {
ConstantThroughputTimer timer = new ConstantThroughputTimer();
assertEquals(0,timer.getCalcModeInt());// Assume this thread only
timer.setThroughput(60.0);// 1 per second
long delay = timer.delay(); // Initialise
- assertEquals(0,delay);
- Thread.sleep(500);
- long diff=Math.abs(timer.delay()-500);
+ assertEquals(0,delay); // First one runs immediately
+ simulationClock.increaseTime(500);
+ delay = timer.delay();
+ log.info("testTimer1: new delay = " + delay);
+ long diff=Math.abs(delay-500);
assertTrue("Delay is approximately 500",diff<=50);
}
@@ -51,9 +67,11 @@
ConstantThroughputTimer timer = new ConstantThroughputTimer();
assertEquals(0,timer.getCalcModeInt());// Assume this thread only
timer.setThroughput(60.0);// 1 per second
- assertEquals(1000,timer.calculateCurrentTarget(0)); // Should delay for 1 second
+ assertEquals(0, timer.delay()); // First one runs immediately
+ assertEquals(1000,timer.delay()); // Should delay for 1 second
+ simulationClock.increaseTime(1000);
timer.setThroughput(60000.0);// 1 per milli-second
- assertEquals(1,timer.calculateCurrentTarget(0)); // Should delay for 1 milli-second
+ assertEquals(1,timer.delay()); // Should delay for 1 milli-second
}
public void testTimer3() throws Exception {
@@ -67,15 +85,18 @@
}
assertEquals(10,JMeterContextService.getNumberOfThreads());
timer.setThroughput(600.0);// 10 per second
- assertEquals(1000,timer.calculateCurrentTarget(0)); // Should delay for 1 second
+ assertEquals(0, timer.delay()); // First one runs immediately
+ assertEquals(1000,timer.delay()); // Should delay for 1 second
+ simulationClock.increaseTime(1000);
timer.setThroughput(600000.0);// 10 per milli-second
- assertEquals(1,timer.calculateCurrentTarget(0)); // Should delay for 1 milli-second
+ assertEquals(1,timer.delay()); // Should delay for 1 milli-second
+ simulationClock.increaseTime(1);
for(int i=1; i<=990; i++){
TestJMeterContextService.incrNumberOfThreads();
}
assertEquals(1000,JMeterContextService.getNumberOfThreads());
timer.setThroughput(60000000.0);// 1000 per milli-second
- assertEquals(1,timer.calculateCurrentTarget(0)); // Should delay for 1 milli-second
+ assertEquals(1,timer.delay()); // Should delay for 1 milli-second
}
public void testTimerBSH() throws Exception {
--- test/src/org/apache/jmeter/timers/simulator_mode1.txt (revision 0)
+++ test/src/org/apache/jmeter/timers/simulator_mode1.txt (revision 0)
@@ -0,0 +1,31 @@
+#
+# Constant Throughput Timer Simulator file
+# See simulator_template.txt for full explanation of files contents.
+#
+
+# calcMode.1=this thread only
+Simulation Time, 1m1t1[5000], 2m1t1[3000], 3m1t2[10000],
+ 0, d=0, d=0, d=0, # For non-shared Constant Throughput Timers the first request will be at time 0 with no delay.
+ 1000, , , ,
+ 2000, , , ,
+ 3000, d=2000, X, , # Here timer 1's request has completed, so there is a delay of 2000ms until the next optimal request boundary. It is also timer 2's optimal boundary, but it has been missed this time.
+ 4000, , d=0, , # timer 2 finally finshes, having missed the optimal boundary there is no delay in starting the next request.
+ 5000, X, , ,
+ 6000, d=4000, X, , # timer 1 finishes, there is a delay of 4000ms until the next optimal boundary.
+ 6999, , d=1, , # timer 2 finishes, with 1ms to spare before the next optimal boundary.
+ 7000, , , , # Note: at 3000 msPerRequest the second optimal boundary is 6000, BUT the last request finished at 4000, so this makes the bounday 7000 (4000 + 3000)
+ 8000, , , ,
+ 9000, , X, ,
+ 10000, X, , X, # Note 'X' is for readability only, from this point on only interested in timer 3 so no more X's have been marked for timer 1 and 2
+ 50000, , , X,
+ 51000, , , d=0, # timer 3 finally finishes. A 10,000 msPerRequest means 6 per minute. But there are only 10s left in the current minute
+ 52000, , , , # Note that Constant Throughput Timer does not average out request times to achieve throughput,
+ 53000, , , , # if you miss more than one optimal boundary then that time slice is gone forever and will never be caught up.
+ 54000, , , d=7000, # i.e. Even though the Timer is requesting another slice, the delay wont be d=0 to ensure we fit more requests in the minute
+ 55000, , , , # but instead will be the difference between now and the next boundary.
+ 56000, , , , # And the delay is 10000 from the previous time, i.e. 54000 + 10000 = 61000
+ 57000, , , ,
+ 58000, , , ,
+ 59000, , , ,
+ 60000, , , X,
+ 61000, , , ,
--- test/src/org/apache/jmeter/timers/ConstantThroughputTimerTest.java (revision 0)
+++ test/src/org/apache/jmeter/timers/ConstantThroughputTimerTest.java (revision 0)
@@ -0,0 +1,612 @@
+/*
+ * 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.timers;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jmeter.junit.JMeterTestCase;
+import org.apache.jmeter.threads.JMeterContextService;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+public class ConstantThroughputTimerTest extends JMeterTestCase {
+
+ private static final Logger LOG = LoggingManager.getLoggerForClass();
+
+ /**
+ * Simulation Clock used to manage "SystemClock" time during tests
+ */
+ private SimulationClock simulationClock;
+
+ public ConstantThroughputTimerTest(String arg0) {
+ super(arg0);
+ }
+
+ /**
+ * + * This "simulates" which test data has the next event. In order to handle + * shared mode appropriately the "nextEvent" needs to be moved to the end of + * the list otherwise the same test data will be returned each time and none + * of the other "threads" (which sit after this in the list) will get a + * turn. + *
+ * + * @param testDataList + * the list of test data + * @return the test data that contains the next event in the simulation, or + * null if the are no more events. Non-null next events will be + * moved to the end of theList
+ */
+ private ConstantThroughputTimerTestData getNextEvent(
+ ListThroughputInfo.systemClock
to be a
+ * SimulationClock
.
+ *
+ * @throws Exception
+ * setUp failures
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ simulationClock = new SimulationClock();
+ ThroughputInfo.setSystemClock(simulationClock);
+
+ ConstantThroughputTimerTestData
+ .setupJMeterContextService_threadContext();
+ }
+
+ /**
+ * Resets the ThroughputInfo.systemClock
to
+ * ThroughputInfo.SystemClock
+ *
+ * @throws Exception
+ * tearDown failures
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ ThroughputInfo.setSystemClock(new ThroughputInfo.SystemClock());
+ super.tearDown();
+ }
+
+ /**
+ * Mode 1 "This Thead Only", In this test threads take
+ * msPerRequest
to complete. i.e. on the optimal boundaries.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode1ThisThreadOnly() throws Exception {
+ LOG.info("testDelayMode1ThisThreadOnly");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(1);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_1);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(5000, 0));
+ testData.addEvent(new SimulationEvent(10000, 0));
+ testData.addEvent(new SimulationEvent(15000, 0));
+ testData.addEvent(new SimulationEvent(20000, 0));
+ testData.addEvent(new SimulationEvent(25000, 0));
+ testData.addEvent(new SimulationEvent(30000, 0));
+ testData.addEvent(new SimulationEvent(35000, 0));
+ testData.addEvent(new SimulationEvent(40000, 0));
+ testData.addEvent(new SimulationEvent(45000, 0));
+ testData.addEvent(new SimulationEvent(50000, 0));
+ testData.addEvent(new SimulationEvent(55000, 0));
+ testData.addEvent(new SimulationEvent(60000, 0));
+
+ ListmsPerRequest * AllActiveThread Count
.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode2AllActiveThreads_ManyThreads() throws Exception {
+ LOG.info("testDelayMode2AllActiveThreads_ManyThreads");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(200);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_2);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 1, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 2, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 3, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 4, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 5, 0));
+
+ ListmsPerRequest * AllActiveThread Count
, for one thread is the
+ * same as Mode 1.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode2AllActiveThreads_OneThread() throws Exception {
+ LOG.info("testDelayMode2AllActiveThreads_OneThread");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(1);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_2);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(5000, 0));
+ testData.addEvent(new SimulationEvent(10000, 0));
+ testData.addEvent(new SimulationEvent(15000, 0));
+ testData.addEvent(new SimulationEvent(20000, 0));
+ testData.addEvent(new SimulationEvent(25000, 0));
+ testData.addEvent(new SimulationEvent(30000, 0));
+ testData.addEvent(new SimulationEvent(35000, 0));
+ testData.addEvent(new SimulationEvent(40000, 0));
+ testData.addEvent(new SimulationEvent(45000, 0));
+ testData.addEvent(new SimulationEvent(50000, 0));
+ testData.addEvent(new SimulationEvent(55000, 0));
+ testData.addEvent(new SimulationEvent(60000, 0));
+
+ ListmsPerRequest * AllActiveThread Count
.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode2AllActiveThreads_TwoThreads() throws Exception {
+ LOG.info("testDelayMode2AllActiveThreads_TwoThreads");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(2);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_2);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(10000, 0));
+ testData.addEvent(new SimulationEvent(20000, 0));
+ testData.addEvent(new SimulationEvent(30000, 0));
+ testData.addEvent(new SimulationEvent(40000, 0));
+ testData.addEvent(new SimulationEvent(50000, 0));
+ testData.addEvent(new SimulationEvent(60000, 0));
+
+ ListmsPerRequest * active ThreadsInThreadGroup Count
.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode3AllActiveThreadsInThreadGroup_ManyThreads()
+ throws Exception {
+ LOG.info("testDelayMode3AllActiveThreadsInThreadGroup_ManyThreads");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(200);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_3);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 1, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 2, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 3, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 4, 0));
+ testData.addEvent(new SimulationEvent(5000 * 200 * 5, 0));
+
+ ListmsPerRequest * ThreadsInThreadGroup Count
. For 1 Thread this
+ * is the same as Mode 1.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode3AllActiveThreadsInThreadGroup_OneThread()
+ throws Exception {
+ LOG.info("testDelayMode3AllActiveThreadsInThreadGroup_OneThread");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(1);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_3);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(5000, 0));
+ testData.addEvent(new SimulationEvent(10000, 0));
+ testData.addEvent(new SimulationEvent(15000, 0));
+ testData.addEvent(new SimulationEvent(20000, 0));
+ testData.addEvent(new SimulationEvent(25000, 0));
+ testData.addEvent(new SimulationEvent(30000, 0));
+ testData.addEvent(new SimulationEvent(35000, 0));
+ testData.addEvent(new SimulationEvent(40000, 0));
+ testData.addEvent(new SimulationEvent(45000, 0));
+ testData.addEvent(new SimulationEvent(50000, 0));
+ testData.addEvent(new SimulationEvent(55000, 0));
+ testData.addEvent(new SimulationEvent(60000, 0));
+
+ ListmsPerRequest * ThreadsInThreadGroup Count
.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode3AllActiveThreadsInThreadGroup_TwoThreads()
+ throws Exception {
+ LOG.info("testDelayMode3AllActiveThreadsInThreadGroup_TwoThreads");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(2);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_3);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(10000, 0));
+ testData.addEvent(new SimulationEvent(20000, 0));
+ testData.addEvent(new SimulationEvent(30000, 0));
+ testData.addEvent(new SimulationEvent(40000, 0));
+ testData.addEvent(new SimulationEvent(50000, 0));
+ testData.addEvent(new SimulationEvent(60000, 0));
+
+ ListmsPerRequest
but each thread shares the
+ * previousTime
a request was invoked.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode4AllActiveThreadsShared_OneThread()
+ throws Exception {
+ LOG.info("testDelayMode4AllActiveThreadsShared");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(1);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_4);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(5000, 0));
+ testData.addEvent(new SimulationEvent(10000, 0));
+ testData.addEvent(new SimulationEvent(15000, 0));
+ testData.addEvent(new SimulationEvent(20000, 0));
+ testData.addEvent(new SimulationEvent(25000, 0));
+ testData.addEvent(new SimulationEvent(30000, 0));
+ testData.addEvent(new SimulationEvent(35000, 0));
+ testData.addEvent(new SimulationEvent(40000, 0));
+ testData.addEvent(new SimulationEvent(45000, 0));
+ testData.addEvent(new SimulationEvent(50000, 0));
+ testData.addEvent(new SimulationEvent(55000, 0));
+ testData.addEvent(new SimulationEvent(60000, 0));
+
+ ListmsPerRequest
but each thread in the thread group
+ * shares the previousTime
a request was invoked.
+ *
+ * @throws Exception
+ * test failures
+ */
+ public void testDelayMode5AllActiveThreadsInThreadGroupShared_OneThread()
+ throws Exception {
+ LOG.info("testDelayMode5AllActiveThreadsInThreadGroupShared");
+
+ ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
+ testData.setThroughput(12.0);
+ testData.setNumberOfThreadsInThreadGroup(1);
+ testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_5);
+
+ testData.addEvent(new SimulationEvent(0, 0));
+ testData.addEvent(new SimulationEvent(5000, 0));
+ testData.addEvent(new SimulationEvent(10000, 0));
+ testData.addEvent(new SimulationEvent(15000, 0));
+ testData.addEvent(new SimulationEvent(20000, 0));
+ testData.addEvent(new SimulationEvent(25000, 0));
+ testData.addEvent(new SimulationEvent(30000, 0));
+ testData.addEvent(new SimulationEvent(35000, 0));
+ testData.addEvent(new SimulationEvent(40000, 0));
+ testData.addEvent(new SimulationEvent(45000, 0));
+ testData.addEvent(new SimulationEvent(50000, 0));
+ testData.addEvent(new SimulationEvent(55000, 0));
+ testData.addEvent(new SimulationEvent(60000, 0));
+
+ ListmsPerRequest
.
+# The difference with the simulator in calc mode "all active threads in current thread group (shared)"
+# is that each thread group will get a single event stream shared amongst the threads in the thread group,
+# instead of each thread getting a copy of the event stream.
+# For "all active threads in current thread group (shared)" each timer uses its own delay,
+# but the calculation is based on when the last thread within the thread group was run at.
+
+# delay = target time <= current time ? 0 : target time - simulation time
+# where target time = previous time + msPerRequest
+Simulation Time, 1m5t1[5000], 2m5t3[3000], 3m5t5[10000],
+ 0, d=0, d=0, d=0, # For "all active threads in current thread group (shared)" Constant Throughput Timers only the first thread in each thread group will be at time 0 with no delay.
+ 1000, , , , # Subsequent Threads delays are calculated based on the previous time and each thread in the thread group shares the event stream.
+ 2000, , d=1000, , # timer 2 : target time = 0 + 3000 = 3000; delay = 3000 - 2000 = 1000
+ 3000, , X, ,
+ 4000, d=1000, , , # timer 1 : target time = 0 + 5000 = 5000; delay = 5000 - 4000 = 1000
+ 5000, X, , ,
+ 6000, , d=0, , # timer 2 : target time = 3000 + 3000 = 6000; delay = 0
+ 7000, , , d=3000, # timer 3 : target time = 0 + 10000 = 10000; delay = 10000 - 7000 = 3000
+ 8000, , , ,
+ 9000, , X, ,
+ 10000, X, d=0, X, # timer 2 : target time = 6000 + 3000 = 9000; delay = 0
+ 11000, d=0, d=2000, , # timer 2 : target time = 10000 + 3000 = 13000; delay = 13000 - 11000 = 2000
+ 12000, , X, ,
+ 13000, , d=3000, , # timer 2 : target time = 13000 + 3000 = 16000; delay = 16000 - 13000 = 3000
+ 14000, , , ,
+ 15000, X, X, ,
+ 16000, , , d=4000, # timer 3 : target time = 10000 + 10000 = 20000; delay = 20000 - 16000 = 4000
+ 17000, , , ,
+ 18000, , X, d=12000, # timer 3 : target time = 20000 + 10000 = 30000; delay = 30000 - 18000 = 12000
+ 19000, , , ,
+ 20000, X, , X,
+ 21000, , X, ,
+ 22000, , , ,
+ 23000, , , ,
+ 24000, , X, ,
+ 25000, X, , ,
+ 26000, , , ,
+ 27000, , X, ,
+ 28000, , , ,
+ 29000, , , ,
+ 30000, X, X, X,
+ 31000, , , ,
+ 32000, , , ,
+ 33000, , , ,
+ 34000, , , ,
+ 35000, , , ,
+ 36000, , , ,
+ 37000, , , ,
+ 38000, , , ,
+ 39000, , , ,
+ 40000, , , X,
+ 41000, , , d=0, # timer 3 : target time = 30000 + 10000 = 40000; delay = 0
--- test/src/org/apache/jmeter/timers/SimulationClock.java (revision 0)
+++ test/src/org/apache/jmeter/timers/SimulationClock.java (revision 0)
@@ -0,0 +1,130 @@
+/*
+ * 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.timers;
+
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * A Simluation Clock used in unit testing instead of java.lang.System
+ */
+public class SimulationClock extends ThroughputInfo.SystemClock {
+
+ private static final Logger LOG = LoggingManager.getLoggerForClass();
+
+ /**
+ * + * See {@link ThroughputInfo#calculateDelay(long)}. + *
+ * This needs to be set to something larger than the first delay expected. + * Setting to Jan 1 2000 0:00 + */ + private long intialTime = 946647000000L; + + /** + * When was the current time last logged, so that the it is only logged when + * the time changes. + */ + private long lastLoggedCurrentTime = 0L; + + /** + * The offset from the initial time. + */ + private long offset = 0L; + + /** + * @returninitialTime + offset
+ */
+ @Override
+ public long getCurrentTime() {
+ logTime();
+ return getCurrentTimeInternal();
+ }
+
+ /**
+ * @return the current time used internally by other code.
+ */
+ private long getCurrentTimeInternal() {
+ return intialTime + offset;
+ }
+
+ /**
+ * @return the offset
+ */
+ public long getOffset() {
+ return offset;
+ }
+
+ /**
+ * @param increment
+ * the amount in milliseconds to increment the simulation clock
+ * by
+ */
+ public void increaseTime(long increment) {
+ if (increment < 0) {
+ throw new IllegalStateException(
+ "Negative increments are not allowed");
+ }
+ offset += increment;
+ logTime();
+ }
+
+ /**
+ * Log the time, but only if it hasn't changed since the last time it was
+ * logged.
+ */
+ private void logTime() {
+ long currentTime = getCurrentTimeInternal();
+ if (lastLoggedCurrentTime != currentTime) {
+ LOG.info(toString());
+ lastLoggedCurrentTime = currentTime;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "Offset = " + offset;
+ }
+
+ /**
+ * @param initialTime
+ * new initial simulation time
+ */
+ public void setInitialTime(long initialTime) {
+ this.intialTime = initialTime;
+ logTime();
+ }
+
+ /**
+ * @param offset
+ * the offset to set
+ */
+ public void setOffset(long offset) {
+ if (offset < this.offset) {
+ throw new IllegalStateException("Offset (" + offset
+ + ") must be larger than the current offset )"
+ + this.offset + ".");
+ }
+ this.offset = offset;
+ logTime();
+ }
+
+}
--- test/src/org/apache/jmeter/timers/simulator_template.txt (revision 0)
+++ test/src/org/apache/jmeter/timers/simulator_template.txt (revision 0)
@@ -0,0 +1,75 @@
+#
+# Constant Throughput Timer Simulator template file
+#
+# Lines starting with # are comments and ignored.
+# Lines can also include # and the rest of the line is considered a comment.
+#
+# The first line is the Timer declarations.
+# The first line's column is ignored as this is the header name for the clock time
+# Each other column is of the form
+# msPerRequest * AllActiveThread Count
.
+# Timer 1 delay = 5000 * 9 = 45,000
+# Timer 2 delay = 3000 * 9 = 27,000
+# Timer 3 delay = 10000 * 9 = 90,000
+
+# delay = target time <= current time ? 0 : target time - simulation time
+# where target time = previous time + msPerRequest
+Simulation Time, 1m2t1[5000], 2m2t3[3000], 3m2t5[10000],
+ 0, d=0, d=0, d=0, # For non-shared Constant Throughput Timers the first request will be at time 0 with no delay.
+ 4000, , d=23000, , # timer 2 : target time = 0 + 27000 = 270000; delay = 27000 - 4000 = 23000
+ 5000, d=40000, , , # timer 1 : target time = 0 + 45000 = 45000; delay = 45000 - 5000 = 40000
+ 27000, , X, ,
+ 30000, , d=24000, , # timer 2 : target time = 27000 + 27000 = 54000; delay = 54000 - 30000 = 24000
+ 45000, X, , ,
+ 54000, , X, ,
+ 70000, , , d=20000, # timer 3 : target time = 0 + 90000 = 90000; delay = 90000 - 70000 = 20000
+ 81000, , X, ,
+ 90000, X, , X,
+ 108000, , X, ,
+ 135000, X, , ,
+ 180000, X, , X,
+ 269500, , , d=0, # timer 3 : target time = 90000 + 90000 = 180000; delay = 0
+ 270000, X, , X,
+
--- test/src/org/apache/jmeter/timers/SimulationEvent.java (revision 0)
+++ test/src/org/apache/jmeter/timers/SimulationEvent.java (revision 0)
@@ -0,0 +1,62 @@
+/*
+ * 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.timers;
+
+/**
+ *
+ * A Simulation Event for ConstantThroughputTimer
.
+ *
+ * Events happen at the specified clockOffset
and expect that the
+ * ConstantThroughputTimer
will have a delay of delay
.
+ *
ConstantThroughputTimer
+ * when calculating the next time an event will occur
+ */
+ public int getDelay() {
+ return delay;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "SimulationEvent [clockOffset=" + clockOffset + ", delay="
+ + delay + "]";
+ }
+
+}
--- test/src/org/apache/jmeter/threads/MockJMeterContext.java (revision 0)
+++ test/src/org/apache/jmeter/threads/MockJMeterContext.java (revision 0)
@@ -0,0 +1,242 @@
+/*
+ * 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.apache.jmeter.engine.StandardJMeterEngine;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.samplers.Sampler;
+
+/**
+ *
+ * A Mock implementation of JMeterContext
+ *
+ * The normal way of obtaining JMeterContext
is via
+ * {@link JMeterContextService#getContext()} which relies on
+ * ThreadLocal
variables. In unit tests setting up threads is
+ * difficult. This Mock allows you to "swap out" what should be returned during
+ * your unit tests so that one thread can be used to run the tests. Setting the
+ * delegate
allows you to do the "swap out"
+ *
JMeterContext
since its
+ * visibility is "default" and not available outside of this
+ * package.
+ */
+ public static JMeterContext newJMeterContext() {
+ return new JMeterContext();
+ }
+
+ /**
+ * @return the delegate
+ */
+ public JMeterContext getDelegate() {
+ return delegate;
+ }
+
+ /**
+ * @param delegate
+ * the delegate to set
+ */
+ public void setDelegate(JMeterContext delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * @return
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ /**
+ *
+ * @see org.apache.jmeter.threads.JMeterContext#clear()
+ */
+ public void clear() {
+ delegate.clear();
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getVariables()
+ */
+ public JMeterVariables getVariables() {
+ return delegate.getVariables();
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getReadBuffer()
+ */
+ public byte[] getReadBuffer() {
+ return delegate.getReadBuffer();
+ }
+
+ /**
+ * @param vars
+ * @see org.apache.jmeter.threads.JMeterContext#setVariables(org.apache.jmeter.threads.JMeterVariables)
+ */
+ public void setVariables(JMeterVariables vars) {
+ delegate.setVariables(vars);
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getPreviousResult()
+ */
+ public SampleResult getPreviousResult() {
+ return delegate.getPreviousResult();
+ }
+
+ /**
+ * @param result
+ * @see org.apache.jmeter.threads.JMeterContext#setPreviousResult(org.apache.jmeter.samplers.SampleResult)
+ */
+ public void setPreviousResult(SampleResult result) {
+ delegate.setPreviousResult(result);
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getCurrentSampler()
+ */
+ public Sampler getCurrentSampler() {
+ return delegate.getCurrentSampler();
+ }
+
+ /**
+ * @param sampler
+ * @see org.apache.jmeter.threads.JMeterContext#setCurrentSampler(org.apache.jmeter.samplers.Sampler)
+ */
+ public void setCurrentSampler(Sampler sampler) {
+ delegate.setCurrentSampler(sampler);
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getPreviousSampler()
+ */
+ public Sampler getPreviousSampler() {
+ return delegate.getPreviousSampler();
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getThreadNum()
+ */
+ public int getThreadNum() {
+ return delegate.getThreadNum();
+ }
+
+ /**
+ * @param threadNum
+ * @see org.apache.jmeter.threads.JMeterContext#setThreadNum(int)
+ */
+ public void setThreadNum(int threadNum) {
+ delegate.setThreadNum(threadNum);
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getThread()
+ */
+ public JMeterThread getThread() {
+ return delegate.getThread();
+ }
+
+ /**
+ * @param obj
+ * @return
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ return delegate.equals(obj);
+ }
+
+ /**
+ * @param thread
+ * @see org.apache.jmeter.threads.JMeterContext#setThread(org.apache.jmeter.threads.JMeterThread)
+ */
+ public void setThread(JMeterThread thread) {
+ delegate.setThread(thread);
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getThreadGroup()
+ */
+ public AbstractThreadGroup getThreadGroup() {
+ return delegate.getThreadGroup();
+ }
+
+ /**
+ * @param threadgrp
+ * @see org.apache.jmeter.threads.JMeterContext#setThreadGroup(org.apache.jmeter.threads.AbstractThreadGroup)
+ */
+ public void setThreadGroup(AbstractThreadGroup threadgrp) {
+ delegate.setThreadGroup(threadgrp);
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#getEngine()
+ */
+ public StandardJMeterEngine getEngine() {
+ return delegate.getEngine();
+ }
+
+ /**
+ * @param engine
+ * @see org.apache.jmeter.threads.JMeterContext#setEngine(org.apache.jmeter.engine.StandardJMeterEngine)
+ */
+ public void setEngine(StandardJMeterEngine engine) {
+ delegate.setEngine(engine);
+ }
+
+ /**
+ * @return
+ * @see org.apache.jmeter.threads.JMeterContext#isSamplingStarted()
+ */
+ public boolean isSamplingStarted() {
+ return delegate.isSamplingStarted();
+ }
+
+ /**
+ * @param b
+ * @see org.apache.jmeter.threads.JMeterContext#setSamplingStarted(boolean)
+ */
+ public void setSamplingStarted(boolean b) {
+ delegate.setSamplingStarted(b);
+ }
+
+ /**
+ * @return
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return delegate.toString();
+ }
+}