View | Details | Raw Unified | Return to bug 51480
Collapse All | Expand All

(-)src/components/org/apache/jmeter/timers/ThroughputInfo.java (+103 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
package org.apache.jmeter.timers;
19
20
import java.io.Serializable;
21
22
/**
23
 * Manages the throughput information in a thread safe way.
24
 */
25
public class ThroughputInfo implements Serializable {
26
    private static final long serialVersionUID = 1;
27
28
	/**
29
	 * Extracted out for unit testing. See class javadoc.
30
	 */
31
	private static SystemClock SYSTEM_CLOCK = new SystemClock();
32
33
	/**
34
	 * Extracted out for unit testing. Java should optimize this away in
35
	 * production.
36
	 */
37
	protected static class SystemClock {
38
39
		/**
40
		 * @return <code>System.currentTimeMillis</code>
41
		 */
42
		public long getCurrentTime() {
43
			return System.currentTimeMillis();
44
		}
45
	}
46
47
	/**
48
	 * Only used for unit testing to set a simulation clock instead of
49
	 * java.lang.System.
50
	 *
51
	 * @param systemClock
52
	 *            the system clock to use
53
	 */
54
	protected static void setSystemClock(SystemClock systemClock) {
55
		SYSTEM_CLOCK = systemClock;
56
	}
57
58
	/**
59
	 * The time, in milliseconds, when the last scheduled event occurred.
60
	 *
61
	 * @GuardedBy("this")
62
	 */
63
	private long lastScheduledTime = 0;
64
65
	/**
66
	 * <p>
67
	 * Calculate the delay needed to reach the target time of
68
	 * <code>lastScheduledTime + delay</code>
69
	 * </p>
70
	 *
71
	 * @param delay
72
	 *            the delay before the next scheduled event
73
	 * @return return 0 if the current time has already past the target time,
74
	 *         target time - current time otherwise.
75
	 */
76
	public synchronized long calculateDelay(long delay) {
77
		final long currentTime = SYSTEM_CLOCK.getCurrentTime();
78
79
		/*
80
		 * If lastScheduledTime is zero, then target will be in the past. This
81
		 * is what we want, so first sample is run without a delay. (This is
82
		 * only true if the currentTime is at greater than <code>delay</code>
83
		 * seconds after midnight, January 1, 1970 UTC)
84
		 */
85
		long targetTime = lastScheduledTime + delay;
86
		if (currentTime > targetTime) {
87
			// We're behind schedule -- try to catch up:
88
			lastScheduledTime = currentTime;
89
			return 0;
90
		}
91
		lastScheduledTime = targetTime;
92
		return targetTime - currentTime;
93
94
	}
95
96
	/**
97
	 * Reset the <code>lastScheduledTime</code> to zero.
98
	 */
99
	public synchronized void reset() {
100
		lastScheduledTime = 0;
101
	}
102
103
}
(-)src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java (-74 / +75 lines)
Lines 18-24 Link Here
18
18
19
package org.apache.jmeter.timers;
19
package org.apache.jmeter.timers;
20
20
21
import java.util.Map;
22
import java.util.concurrent.ConcurrentHashMap;
21
import java.util.concurrent.ConcurrentHashMap;
23
22
24
import org.apache.jmeter.engine.event.LoopIterationEvent;
23
import org.apache.jmeter.engine.event.LoopIterationEvent;
Lines 37-61 Link Here
37
 * samples per unit of time approaches a given constant as much as possible.
36
 * samples per unit of time approaches a given constant as much as possible.
38
 *
37
 *
39
 * There are two different ways of pacing the requests:
38
 * There are two different ways of pacing the requests:
40
 * - delay each thread according to when it last ran
39
 * <ul>
41
 * - delay each thread according to when any thread last ran
40
 * <li>delay each thread according to when it last ran</li>
41
 * <li>delay each thread according to when any thread last ran</li>
42
 * </ul>
42
 */
43
 */
43
public class ConstantThroughputTimer extends AbstractTestElement implements Timer, TestListener, TestBean {
44
public class ConstantThroughputTimer extends AbstractTestElement implements Timer, TestListener, TestBean {
44
    private static final long serialVersionUID = 3;
45
    private static final long serialVersionUID = 4;
45
46
46
    private static class ThroughputInfo{
47
    private static final int CALC_MODE_1_THIS_THREAD_ONLY = 0;
47
        final Object MUTEX = new Object();
48
    private static final int CALC_MODE_2_ALL_ACTIVE_THREADS = 1;
48
        long lastScheduledTime = 0;
49
    private static final int CALC_MODE_3_ALL_ACTIVE_THREADS_IN_CURRENT_THREAD_GROUP = 2;
49
    }
50
    private static final int CALC_MODE_4_ALL_ACTIVE_THREADS_SHARED = 3;
51
    private static final int CALC_MODE_5_ALL_ACTIVE_THREADS_IN_CURRENT_THREAD_GROUP_SHARED = 4;
52
50
    private static final Logger log = LoggingManager.getLoggerForClass();
53
    private static final Logger log = LoggingManager.getLoggerForClass();
51
54
52
    private static final double MILLISEC_PER_MIN = 60000.0;
55
    protected static final double MILLISEC_PER_MIN = 60000.0;
53
56
54
    /**
57
    /**
55
     * Target time for the start of the next request. The delay provided by the
58
     * Target time for the start of the next request. The delay provided by the
56
     * timer will be calculated so that the next request happens at this time.
59
     * timer will be calculated so that the next request happens at this time.
57
     */
60
     */
58
    private long previousTime = 0;
61
    private ThroughputInfo throughputInfo = new ThroughputInfo();
59
62
60
    private String calcMode; // String representing the mode
63
    private String calcMode; // String representing the mode
61
                                // (Locale-specific)
64
                                // (Locale-specific)
Lines 71-77 Link Here
71
    private final static ThroughputInfo allThreadsInfo = new ThroughputInfo();
74
    private final static ThroughputInfo allThreadsInfo = new ThroughputInfo();
72
75
73
    //For holding the ThrougputInfo objects for all ThreadGroups. Keyed by AbstractThreadGroup objects
76
    //For holding the ThrougputInfo objects for all ThreadGroups. Keyed by AbstractThreadGroup objects
74
    private final static Map<AbstractThreadGroup, ThroughputInfo> threadGroupsInfoMap =
77
    private final static ConcurrentHashMap<AbstractThreadGroup, ThroughputInfo> threadGroupsInfoMap =
75
        new ConcurrentHashMap<AbstractThreadGroup, ThroughputInfo>();
78
        new ConcurrentHashMap<AbstractThreadGroup, ThroughputInfo>();
76
79
77
80
Lines 109-118 Link Here
109
        return modeInt;
112
        return modeInt;
110
    }
113
    }
111
114
115
    /**
116
     * Setting this has the side effect of sharing <code>throughputInfo</code> if the mode is
117
     * <em>shared</em>.
118
     *
119
     * @param mode
120
     *            the delay calculation mode
121
     */
112
    public void setCalcMode(String mode) {
122
    public void setCalcMode(String mode) {
113
        this.calcMode = mode;
123
        this.calcMode = mode;
114
        // TODO find better way to get modeInt
124
        // TODO find better way to get modeInt
115
        this.modeInt = ConstantThroughputTimerBeanInfo.getCalcModeAsInt(calcMode);
125
        this.modeInt = ConstantThroughputTimerBeanInfo.getCalcModeAsInt(calcMode);
126
127
        switch (modeInt) {
128
        case CALC_MODE_4_ALL_ACTIVE_THREADS_SHARED:
129
            throughputInfo = allThreadsInfo;
130
            break;
131
132
        case CALC_MODE_5_ALL_ACTIVE_THREADS_IN_CURRENT_THREAD_GROUP_SHARED:
133
            final org.apache.jmeter.threads.AbstractThreadGroup group = JMeterContextService
134
                    .getContext().getThreadGroup();
135
            /*
136
             * Share the first thread's throughputInfo
137
             */
138
            threadGroupsInfoMap.putIfAbsent(group, throughputInfo);
139
            throughputInfo = threadGroupsInfoMap.get(group);
140
            break;
141
        }
116
    }
142
    }
117
143
118
    /**
144
    /**
Lines 121-209 Link Here
121
     * @see org.apache.jmeter.timers.Timer#delay()
147
     * @see org.apache.jmeter.timers.Timer#delay()
122
     */
148
     */
123
    public long delay() {
149
    public long delay() {
124
        long currentTime = System.currentTimeMillis();
150
        return throughputInfo.calculateDelay(calculateDelayForMode());
125
126
        /*
127
         * If previous time is zero, then target will be in the past.
128
         * This is what we want, so first sample is run without a delay.
129
        */
130
        long currentTarget = previousTime  + calculateDelay();
131
        if (currentTime > currentTarget) {
132
            // We're behind schedule -- try to catch up:
133
            previousTime = currentTime;
134
            return 0;
135
        }
136
        previousTime = currentTarget;
137
        return currentTarget - currentTime;
138
    }
151
    }
139
152
140
    /**
153
    /**
141
     * @param currentTime
154
     * <p>
142
     * @return new Target time
155
     * Calculate the delay based on the mode
156
     * </p>
157
     *
158
     * @return the delay (how long before another request should be made) in
159
     *         milliseconds
143
     */
160
     */
144
    // TODO - is this used? (apart from test code)
161
    private long calculateDelayForMode() {
145
    protected long calculateCurrentTarget(long currentTime) {
146
        return currentTime + calculateDelay();
147
    }
148
149
    // Calculate the delay based on the mode
150
    private long calculateDelay() {
151
        long delay = 0;
162
        long delay = 0;
152
        // N.B. we fetch the throughput each time, as it may vary during a test
163
        // N.B. we fetch the throughput each time, as it may vary during a test
153
        double msPerRequest = (MILLISEC_PER_MIN / getThroughput());
164
        double msPerRequest = (MILLISEC_PER_MIN / getThroughput());
154
        switch (modeInt) {
165
        switch (modeInt) {
155
        case 1: // Total number of threads
166
        case CALC_MODE_2_ALL_ACTIVE_THREADS:
167
            /*
168
             * Each request is allowed to run every msPerRequest. Each thread
169
             * can run a request, so each thread needs to be delayed by the
170
             * total pool size of threads to keep the expected throughput.
171
             */
156
            delay = (long) (JMeterContextService.getNumberOfThreads() * msPerRequest);
172
            delay = (long) (JMeterContextService.getNumberOfThreads() * msPerRequest);
157
            break;
173
            break;
158
174
159
        case 2: // Active threads in this group
175
        case CALC_MODE_3_ALL_ACTIVE_THREADS_IN_CURRENT_THREAD_GROUP:
176
            /*
177
             * Each request is allowed to run every msPerRequest. Each thread
178
             * can run a request, so each thread needs to be delayed by the
179
             * total pool size of threads to keep the expected throughput.
180
             */
160
            delay = (long) (JMeterContextService.getContext().getThreadGroup().getNumberOfThreads() * msPerRequest);
181
            delay = (long) (JMeterContextService.getContext().getThreadGroup().getNumberOfThreads() * msPerRequest);
161
            break;
182
            break;
162
183
163
        case 3: // All threads - alternate calculation
184
        /*
164
            delay = calculateSharedDelay(allThreadsInfo,(long) msPerRequest);
185
         * The following modes all fall through for the default
186
         */
187
        case CALC_MODE_1_THIS_THREAD_ONLY:
188
        case CALC_MODE_4_ALL_ACTIVE_THREADS_SHARED:
189
        case CALC_MODE_5_ALL_ACTIVE_THREADS_IN_CURRENT_THREAD_GROUP_SHARED:
190
        default:
191
            delay = (long) msPerRequest;
165
            break;
192
            break;
166
167
        case 4: //All threads in this group - alternate calculation
168
            final org.apache.jmeter.threads.AbstractThreadGroup group =
169
                JMeterContextService.getContext().getThreadGroup();
170
            ThroughputInfo groupInfo;
171
            synchronized (threadGroupsInfoMap) {
172
                groupInfo = threadGroupsInfoMap.get(group);
173
                if (groupInfo == null) {
174
                    groupInfo = new ThroughputInfo();
175
                    threadGroupsInfoMap.put(group, groupInfo);
176
                }
177
            }
178
            delay = calculateSharedDelay(groupInfo,(long) msPerRequest);
179
            break;
180
181
        default: // e.g. 0
182
            delay = (long) msPerRequest; // i.e. * 1
183
            break;
184
        }
193
        }
185
        return delay;
194
        return delay;
186
    }
195
    }
187
196
188
    private long calculateSharedDelay(ThroughputInfo info, long milliSecPerRequest) {
189
        final long now = System.currentTimeMillis();
190
        final long calculatedDelay;
191
192
        //Synchronize on the info object's MUTEX to ensure
193
        //Multiple threads don't update the scheduled time simultaneously
194
        synchronized (info.MUTEX) {
195
            final long nextRequstTime = info.lastScheduledTime + milliSecPerRequest;
196
            info.lastScheduledTime = Math.max(now, nextRequstTime);
197
            calculatedDelay = info.lastScheduledTime - now;
198
        }
199
200
        return Math.max(calculatedDelay, 0);
201
    }
202
203
    private synchronized void reset() {
197
    private synchronized void reset() {
204
        allThreadsInfo.lastScheduledTime = 0;
198
        throughputInfo = new ThroughputInfo();
205
        threadGroupsInfoMap.clear();
199
        setCalcMode(calcMode);
206
        previousTime = 0;
207
    }
200
    }
208
201
209
    /**
202
    /**
Lines 234-239 Link Here
234
     * {@inheritDoc}
227
     * {@inheritDoc}
235
     */
228
     */
236
    public void testEnded() {
229
    public void testEnded() {
230
        /*
231
         * There is no way to clean up static variables. The best place to do
232
         * that is in the testEnded() call as this wont affect a running test.
233
         * If these are in testStarted then they affect already initialised
234
         * objects.
235
         */
236
        allThreadsInfo.reset();
237
        threadGroupsInfoMap.clear();
237
    }
238
    }
238
239
239
    /**
240
    /**
(-)test/src/org/apache/jmeter/timers/ConstantThroughPutTimerSimulation.java (+357 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.timers;
20
21
import java.io.IOException;
22
import java.io.InputStream;
23
import java.io.InputStreamReader;
24
import java.io.LineNumberReader;
25
import java.util.ArrayList;
26
import java.util.List;
27
import java.util.regex.Matcher;
28
import java.util.regex.Pattern;
29
30
import org.apache.commons.lang.StringUtils;
31
import org.apache.jorphan.logging.LoggingManager;
32
import org.apache.log.Logger;
33
34
/**
35
 * <p>
36
 * Builds {@link ConstantThroughputTimerTestData} from a simulation file.
37
 * </p>
38
 * <p>
39
 * See simulator_template.txt for an example file explaining the format
40
 * </p>
41
 */
42
public class ConstantThroughPutTimerSimulation {
43
44
	/** Logger */
45
	private static final Logger LOG = LoggingManager.getLoggerForClass();
46
47
	/**
48
	 * The separator of the simulation file is comma
49
	 */
50
	private static final String SEPARATOR = ",";
51
52
	/**
53
	 * Regular expression pattern for the header
54
	 */
55
	private static final Pattern PATTERN_HEADER = Pattern
56
			.compile("(\\d+)m(\\d)t(\\d+)\\[(\\d+)\\]");
57
58
	/**
59
	 * Regular expression pattern for the columns
60
	 */
61
	private static final Pattern PATTERN_COLUMN = Pattern.compile("d=(\\d+)");
62
63
	/**
64
	 *
65
	 * @param simulationFileName
66
	 *            the file name of the simulation. Uses
67
	 *            {@link ClassLoader#getResourceAsStream(String)} to find the
68
	 *            file
69
	 * @return the InputStream containging the contents of the file
70
	 * @throws IOException
71
	 *             failed to obtain file
72
	 */
73
	private InputStream getSimulationFile(String simulationFileName)
74
			throws IOException {
75
		return getClass().getClassLoader().getResourceAsStream(
76
				simulationFileName);
77
	}
78
79
	/**
80
	 * Load the specified <code>simulationFileName</code> (Using
81
	 * {@link ClassLoader#getResourceAsStream(String)}) and return a list of
82
	 * configured TestData representing the simulation.
83
	 *
84
	 * @param simulationFileName
85
	 *            the file name of the simulation. Uses
86
	 *            {@link ClassLoader#getResourceAsStream(String)} to find the
87
	 *            file
88
	 * @return a list of configured TestData
89
	 * @throws IOException
90
	 *             failed to obtain file
91
	 * @throws SimulationParseException
92
	 *             failed to parse simulation file
93
	 */
94
	public List<ConstantThroughputTimerTestData> loadSimulationFile(
95
			String simulationFileName) throws IOException,
96
			SimulationParseException {
97
		return parse(simulationFileName);
98
	}
99
100
	/**
101
	 * @param simulationFileName
102
	 *            the name of the simulation file
103
	 * @return the simulation <code>TestData</code>
104
	 * @throws IOException
105
	 *             failed to load the simulation file
106
	 * @throws SimulationParseException
107
	 *             failed to parse simulation file
108
	 */
109
	private List<ConstantThroughputTimerTestData> parse(
110
			String simulationFileName) throws IOException,
111
			SimulationParseException {
112
		InputStream simulationFile = getSimulationFile(simulationFileName);
113
		if (simulationFile == null) {
114
			throw new SimulationParseException("Unable to locate simulation file: " + simulationFileName, 0);
115
		}
116
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
117
118
		LineNumberReader simulationInput = new LineNumberReader(
119
				new InputStreamReader(simulationFile));
120
		String line = null;
121
122
		boolean parsingBody = false;
123
		try {
124
			while ((line = simulationInput.readLine()) != null) {
125
				line = stripComments(line);
126
				if (StringUtils.isNotBlank(line)) {
127
					if (!parsingBody) {
128
						parseHeader(simulation, line);
129
						parsingBody = true;
130
131
					} else {
132
						parseBody(simulation, line);
133
					}
134
				}
135
			}
136
		} catch (SimulationParseException e) {
137
			e.setLineNumber(simulationInput.getLineNumber());
138
			e.setFileName(simulationFileName);
139
			throw e;
140
		}
141
142
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
143
144
		return simulation;
145
	}
146
147
	/**
148
	 * @param simulation
149
	 *            the simulation list of <code>TestData</code>
150
	 * @param line
151
	 *            the line to parse
152
	 * @throws SimulationParseException
153
	 *             failed to parse simulation file
154
	 */
155
	private void parseBody(List<ConstantThroughputTimerTestData> simulation,
156
			String line) throws SimulationParseException {
157
		String[] columns = line.split(SEPARATOR);
158
		if (columns.length <= 1) {
159
			throw new SimulationParseException("No Events defined",
160
					line.length() + 1);
161
		}
162
163
		String clockTimeAsString = columns[0].trim();
164
		int clockTime = 0;
165
		try {
166
			clockTime = Integer.parseInt(clockTimeAsString);
167
		} catch (NumberFormatException e) {
168
			throw new SimulationParseException(
169
					"Malformed Simulation Clock Time: " + clockTimeAsString,
170
					computeColumnNumber(columns, 0));
171
172
		}
173
174
		for (int i = 1; i < columns.length; i++) {
175
			String column = columns[i].trim();
176
			if (StringUtils.isBlank(column)) {
177
				// ignore blank columns
178
				continue;
179
			}
180
181
			if (i > simulation.size()) {
182
				throw new SimulationParseException("Too many events defined",
183
						computeColumnNumber(columns, i));
184
			}
185
186
			if (column.equalsIgnoreCase("X")) {
187
				// Ignore optimal time boundary indicators
188
				continue;
189
			}
190
191
			Matcher matcher = PATTERN_COLUMN.matcher(column);
192
			if (!matcher.matches()) {
193
				throw new SimulationParseException(
194
						"Malformed delay: " + column, computeColumnNumber(
195
								columns, i));
196
			}
197
			int delay = 0;
198
			try {
199
				delay = Integer.parseInt(matcher.group(1));
200
			} catch (NumberFormatException e) {
201
				throw new SimulationParseException(
202
						"Malformed delay: " + column, computeColumnNumber(
203
								columns, i));
204
			}
205
206
			SimulationEvent event = new SimulationEvent(clockTime, delay);
207
			int simulationIndex = i - 1; /*
208
										 * columnIndex includes clockTime,
209
										 * simulationIndex doesn't
210
										 */
211
			LOG.debug("Adding event to TestData: "
212
					+ simulation.get(simulationIndex).getTimerId() + ", "
213
					+ event);
214
			simulation.get(simulationIndex).addEvent(event);
215
		}
216
217
	}
218
219
	/**
220
	 * @param simulation
221
	 *            the list to build for the simulation
222
	 * @param line
223
	 *            the line to parse
224
	 * @throws SimulationParseException
225
	 *             failed to parse simulation file
226
	 */
227
	private void parseHeader(List<ConstantThroughputTimerTestData> simulation,
228
			String line) throws SimulationParseException {
229
		String[] headers = line.split(SEPARATOR);
230
		if (headers.length <= 1) {
231
			throw new SimulationParseException("No Timers defined",
232
					line.length() + 1);
233
		}
234
		// Ignore the first header as its the Simulation Clock name
235
		for (int i = 1; i < headers.length; i++) {
236
			String header = headers[i].trim();
237
			Matcher matcher = PATTERN_HEADER.matcher(header);
238
			if (!matcher.matches()) {
239
				throw new SimulationParseException("Header " + header
240
						+ " did not match expected format : "
241
						+ PATTERN_HEADER.toString(), computeColumnNumber(
242
						headers, i));
243
			}
244
			String timerId = matcher.group(1);
245
			String mode = ConstantThroughputTimerTestData.RESOURCE_BUNDLE_KEY_CALC_MODE_PREFIX
246
					+ matcher.group(2);
247
			String numberOfThreads = matcher.group(3);
248
			String msPerRequest = matcher.group(4);
249
250
			ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
251
			testData.setTimerId(timerId);
252
			testData.setCalcMode(mode);
253
			try {
254
				testData.setNumberOfThreadsInThreadGroup(Integer
255
						.parseInt(numberOfThreads));
256
			} catch (NumberFormatException e) {
257
				throw new SimulationParseException(
258
						"Malformed number of threads in header: " + header,
259
						computeColumnNumber(headers, i));
260
			}
261
			try {
262
				testData.setMsPerRequest(Integer.parseInt(msPerRequest));
263
			} catch (NumberFormatException e) {
264
				throw new SimulationParseException(
265
						"Malformed msPerRequest in header: " + header,
266
						computeColumnNumber(headers, i));
267
			}
268
269
			LOG.debug(testData.toString());
270
			simulation.add(testData);
271
		}
272
	}
273
274
	/**
275
	 * @param columns
276
	 *            array of columns
277
	 * @param columnIndex
278
	 *            the column index
279
	 * @return
280
	 */
281
	private int computeColumnNumber(String[] columns, int columnIndex) {
282
		int columnNumber = 1;
283
		for (int i = 0; i < columnIndex; i++) {
284
			// extra for the stripped separator character
285
			columnNumber += columns[i].length() + 1;
286
		}
287
		return columnNumber;
288
	}
289
290
	/**
291
	 * @param line
292
	 *            the line to strip comments from
293
	 * @return the line with all characters from a # to the end stripped
294
	 */
295
	private String stripComments(String line) {
296
		return line.replaceAll("#.*", "");
297
	}
298
}
299
300
class SimulationParseException extends Exception {
301
302
	/**
303
	 * serialVersionUID
304
	 */
305
	private static final long serialVersionUID = 1L;
306
307
	/**
308
	 * Offset into the line where the parsing error occurred.
309
	 */
310
	private int offset;
311
312
	/**
313
	 * The lineNumber of where the parsing error occurred.
314
	 */
315
	private int lineNumber;
316
317
	/**
318
	 * The simulation filename of where the parsing error occurred.
319
	 */
320
	private String fileName;
321
322
	public SimulationParseException(String message, int offset) {
323
		super(message);
324
		this.offset = offset;
325
	}
326
327
	@Override
328
	public String getMessage() {
329
		return "Simulation Parsing exception in " + fileName + ":" + lineNumber
330
				+ ":" + offset + " " + super.getMessage();
331
	}
332
333
	/**
334
	 * @param offset
335
	 *            the offset to set
336
	 */
337
	public void setOffset(int offset) {
338
		this.offset = offset;
339
	}
340
341
	/**
342
	 * @param lineNumber
343
	 *            the lineNumber to set
344
	 */
345
	public void setLineNumber(int lineNumber) {
346
		this.lineNumber = lineNumber;
347
	}
348
349
	/**
350
	 * @param fileName
351
	 *            the fileName to set
352
	 */
353
	public void setFileName(String fileName) {
354
		this.fileName = fileName;
355
	}
356
357
}
(-)test/src/org/apache/jmeter/timers/simulator_mode3.txt (+34 lines)
Line 0 Link Here
1
#
2
# Constant Throughput Timer Simulator file
3
# See simulator_template.txt for full explanation of files contents.
4
#
5
6
#  calcMode.3=all active threads in current thread group
7
# Delay is <code>msPerRequest * ThreadsInThreadGroup Count</code>.
8
# Timer 1 delay = 5000 * 1 = 5,000
9
# Timer 2 delay = 3000 * 3 = 9,000
10
# Timer 3 delay = 10000 * 5 = 50,000
11
12
# delay = target time <= current time ? 0 : target time - simulation time
13
#   where target time = previous time + msPerRequest
14
Simulation Time, 1m3t1[5000], 2m3t3[3000], 3m3t5[10000],
15
              0,         d=0,         d=0,          d=0,  # For non-shared Constant Throughput Timers the first request will be at time 0 with no delay.
16
           1000,      d=4000,            ,             ,  # timer 1 : target time = 0 + 5000 = 5000; delay = 5000 - 1000 = 4000
17
           4000,            ,      d=5000,             ,  # timer 2 : target time = 0 + 9000 = 9000; delay = 9000 - 4000 = 5000
18
           5000,           X,            ,             ,
19
           9000,            ,           X,             ,
20
          10000,           X,            ,             ,
21
          15000,           X,            ,             ,
22
          18000,            ,         d=0,             ,  # timer 2 : target time = 9000 + 9000 = 18000; delay = 0
23
          20000,           X,            ,             ,
24
          27000,            ,         d=0,             ,  # timer 2 : target time = 18000 + 9000 = 27000; delay = 0
25
          30000,            ,      d=6000,             ,  # timer 2 : target time = 27000 + 9000 = 36000; delay = 36000 - 30000 = 6000
26
          36000,            ,           X,             ,
27
          45000,           X,            ,             ,
28
          50000,           X,            ,          d=0,  # timer 3 : target time = 0 + 50000 = 50000; delay = 0;
29
          70000,            ,            ,      d=30000,  # timer 3 : target time = 50000 + 50000 = 100000; delay = 100000 - 70000 = 30000
30
         100000,           X,            ,            X,
31
         150500,           X,            ,            X,
32
         150500,            ,            ,          d=0,  # timer 3 : target time = 10000 + 50000 = 150000; delay = 0
33
         200000,           X,            ,            X,
34
(-)test/src/org/apache/jmeter/timers/ConstantThroughputTimerTestData.java (+356 lines)
Line 0 Link Here
1
package org.apache.jmeter.timers;
2
3
import static org.apache.jmeter.timers.Copy_Commons_Lang_2_5_Reflect.getDeclaredField;
4
import static org.apache.jmeter.timers.Copy_Commons_Lang_2_5_Reflect.writeDeclaredStaticField;
5
import static org.junit.Assert.assertEquals;
6
7
import java.lang.reflect.Field;
8
import java.util.ArrayList;
9
import java.util.Collection;
10
import java.util.List;
11
import java.util.ResourceBundle;
12
13
import org.apache.jmeter.testbeans.BeanInfoSupport;
14
import org.apache.jmeter.threads.AbstractThreadGroup;
15
import org.apache.jmeter.threads.JMeterContext;
16
import org.apache.jmeter.threads.JMeterContextService;
17
import org.apache.jmeter.threads.MockJMeterContext;
18
19
/**
20
 * Data class for bundling test data around.
21
 */
22
public class ConstantThroughputTimerTestData {
23
	private static ConstantThroughputTimerBeanInfo BEAN_INFO = new ConstantThroughputTimerBeanInfo();
24
25
	/**
26
	 * this thread only
27
	 */
28
	public static final String CALC_MODE_1 = "calcMode.1";
29
30
	/**
31
	 * all active threads
32
	 */
33
	public static final String CALC_MODE_2 = "calcMode.2";
34
35
	/**
36
	 * all active threads in current thread group
37
	 */
38
	public static final String CALC_MODE_3 = "calcMode.3";
39
40
	/**
41
	 * all active threads (shared)
42
	 */
43
	public static final String CALC_MODE_4 = "calcMode.4";
44
45
	/**
46
	 * all active threads in current thread group (shared)
47
	 */
48
	public static final String CALC_MODE_5 = "calcMode.5";
49
50
	/**
51
	 * Mock JMeterContext which requires a delegate to the actual context.
52
	 * Actual contexts are in <code>ConstantThroughputTimerTestData</code>
53
	 */
54
	private static MockJMeterContext mockJMeterContext = new MockJMeterContext();
55
56
	private static ResourceBundle RESOURCE_BUNDLE = (ResourceBundle) BEAN_INFO
57
			.getBeanDescriptor().getValue(BeanInfoSupport.RESOURCE_BUNDLE);
58
59
	public static final String RESOURCE_BUNDLE_KEY_CALC_MODE_PREFIX = "calcMode.";
60
61
	/**
62
	 * Go through the test data list and create additional <code>TestData</code>
63
	 * instances for each thread in the thread groups.
64
	 *
65
	 * @param testDataList
66
	 *            the test data list
67
	 */
68
	public static void createAdditionalThreads(
69
			List<ConstantThroughputTimerTestData> testDataList) {
70
		List<ConstantThroughputTimerTestData> additional = new ArrayList<ConstantThroughputTimerTestData>();
71
72
		for (int i = 0; i < testDataList.size(); i++) {
73
			ConstantThroughputTimerTestData testData = testDataList.get(i);
74
			additional.addAll(testData.createAddtionalThreads());
75
		}
76
77
		testDataList.addAll(additional);
78
	}
79
80
	/**
81
	 * Setup <code>JMeterContextService.numberOfActiveThreads</code> based on
82
	 * the test data list provided.
83
	 *
84
	 * @param testDataList
85
	 *            the test data list
86
	 * @throws IllegalAccessException
87
	 *             failed to setup
88
	 *             <code>JMeterContextService.numberOfActiveThreads</code>
89
	 */
90
	public static void setupJMeterContextService_numberOfActiveThreads(
91
			List<ConstantThroughputTimerTestData> testDataList)
92
			throws IllegalAccessException {
93
94
		int numberOfActiveThreads = testDataList.size();
95
96
		writeDeclaredStaticField(JMeterContextService.class,
97
				"numberOfActiveThreads", numberOfActiveThreads, true);
98
		int numberOfThreads = JMeterContextService.getNumberOfThreads();
99
		assertEquals(numberOfActiveThreads, numberOfThreads);
100
	}
101
102
	/**
103
	 * Setup JMeterContextService.threadContext to use the "delegate"
104
	 * MockJMeterContext
105
	 *
106
	 * @throws IllegalAccessException
107
	 *             failed to setup JMeterContextService.threadContext
108
	 * @throws IllegalArgumentException
109
	 *             failed to setup JMeterContextService.threadContext
110
	 */
111
	public static void setupJMeterContextService_threadContext()
112
			throws IllegalArgumentException, IllegalAccessException {
113
		Field threadContextField = getDeclaredField(JMeterContextService.class,
114
				"threadContext", true);
115
		@SuppressWarnings("unchecked")
116
		// We know this is the correct type
117
		ThreadLocal<JMeterContext> context = (ThreadLocal<JMeterContext>) threadContextField
118
				.get(null);
119
		context.set(mockJMeterContext);
120
	}
121
122
	private String calcMode;
123
124
	private List<SimulationEvent> events = new ArrayList<SimulationEvent>();
125
126
	private JMeterContext jmeterContext;
127
128
	private long msPerRequest;
129
130
	private double throughput;
131
132
	private ConstantThroughputTimer timer;
133
134
	private String timerId;
135
136
	public ConstantThroughputTimerTestData() {
137
		this.jmeterContext = MockJMeterContext.newJMeterContext();
138
		this.jmeterContext
139
				.setThreadGroup(new org.apache.jmeter.threads.ThreadGroup());
140
141
		ConstantThroughputTimer timer = new ConstantThroughputTimer();
142
		setTimer(timer);
143
	}
144
145
	/**
146
	 * <p>
147
	 * Create a copy of the specified instance.
148
	 * </p>
149
	 * <p>
150
	 * Some properties will be shared from the instance:
151
	 * <ul>
152
	 * <li><code>threadGroup</code>
153
	 * <li><code>events</code>, only if the <code>calcMode</code> is one of the
154
	 * shared modes.
155
	 * </ul>
156
	 * </p>
157
	 *
158
	 * @param original
159
	 *            instance to make a copy from
160
	 * @param count
161
	 *            the instance count being requests
162
	 */
163
	private ConstantThroughputTimerTestData(
164
			ConstantThroughputTimerTestData original, int count) {
165
		/**
166
		 * this() sets up jmeterContext and timer
167
		 */
168
		this();
169
		jmeterContext.setThreadGroup(original.jmeterContext.getThreadGroup());
170
		setCalcMode(original.calcMode);
171
		if (CALC_MODE_4.equals(calcMode) || CALC_MODE_5.equals(calcMode)) {
172
			events = original.events;
173
		} else {
174
			events = new ArrayList<SimulationEvent>();
175
			events.addAll(original.events);
176
		}
177
		setThroughput(original.throughput); // Also sets msPerRequest
178
		timerId = original.timerId + "/" + count;
179
	}
180
181
	/**
182
	 * Make this Test Data the currently active one.
183
	 */
184
	public void activate() {
185
		mockJMeterContext.setDelegate(jmeterContext);
186
	}
187
188
	/**
189
	 * @param event
190
	 *            the event to add to the events list
191
	 */
192
	public void addEvent(SimulationEvent event) {
193
		events.add(event);
194
	}
195
196
	/**
197
	 * <p>
198
	 * Uses the JMeter <code>numberOfThreads</code> (i.e. active threads in the
199
	 * thread group) not the property <code>NumThreads</code>, which is on the
200
	 * test plan.
201
	 * </p>
202
	 *
203
	 * @return a list (potentially empty) for any additional threads, as defined
204
	 *         in the <code>numberOfThreadsInThreadGroup</code>
205
	 */
206
	private Collection<ConstantThroughputTimerTestData> createAddtionalThreads() {
207
		List<ConstantThroughputTimerTestData> additional = new ArrayList<ConstantThroughputTimerTestData>();
208
209
		int numberOfThreadsInThreadGroup = jmeterContext.getThreadGroup()
210
				.getNumberOfThreads();
211
		for (int i = 1; i < numberOfThreadsInThreadGroup; i++) {
212
			additional.add(new ConstantThroughputTimerTestData(this, i + 1));
213
		}
214
215
		return additional;
216
	}
217
218
	/**
219
	 * @return the timer
220
	 */
221
	public ConstantThroughputTimer getTimer() {
222
		return timer;
223
	}
224
225
	/**
226
	 * @return the timerId
227
	 */
228
	public String getTimerId() {
229
		return timerId;
230
	}
231
232
	/**
233
	 * @return peek at the first event without removing it
234
	 */
235
	public SimulationEvent peekFirstEvent() {
236
		return events.isEmpty() ? null : events.get(0);
237
	}
238
239
	/**
240
	 * @return remove the first event
241
	 */
242
	public SimulationEvent removeFirstEvent() {
243
		return events.isEmpty() ? null : events.remove(0);
244
	}
245
246
	/**
247
	 * Setting the calcMode will also <code>activate</code> this Test Data.
248
	 *
249
	 * @param mode
250
	 *            the mode to set
251
	 */
252
	public void setCalcMode(String mode) {
253
		activate();
254
		this.calcMode = mode;
255
		String modeStringFromResourceBundle = RESOURCE_BUNDLE.getString(mode);
256
		timer.setCalcMode(modeStringFromResourceBundle);
257
	}
258
259
	/**
260
	 * <p>
261
	 * Note: Will also set <code>throughput</code> and update the
262
	 * <code>timer</code>
263
	 * </p>
264
	 *
265
	 * @param msPerRequest
266
	 *            the msPerRequest to set
267
	 */
268
	public void setMsPerRequest(long msPerRequest) {
269
		setThroughput(ConstantThroughputTimer.MILLISEC_PER_MIN / msPerRequest);
270
	}
271
272
	/**
273
	 * <p>
274
	 * Sets the JMeter <code>numberOfThreads</code> (i.e. active threads in the
275
	 * thread group) not the property <code>NumThreads</code>, which is on the
276
	 * test plan.
277
	 * </p>
278
	 *
279
	 * @param numberOfThreadsInThreadGroup
280
	 *            the number of threads in the thread group
281
	 * @throws IllegalAccessException
282
	 *             failed to set AbstractThreadGroup.numberOfThreads property
283
	 */
284
	public void setNumberOfThreadsInThreadGroup(int numberOfThreadsInThreadGroup) {
285
		Field numberOfThreadsField = Copy_Commons_Lang_2_5_Reflect
286
				.getDeclaredField(AbstractThreadGroup.class, "numberOfThreads",
287
						true);
288
		try {
289
			Copy_Commons_Lang_2_5_Reflect.writeField(numberOfThreadsField,
290
					jmeterContext.getThreadGroup(),
291
					numberOfThreadsInThreadGroup, false);
292
		} catch (IllegalAccessException e) {
293
			throw new RuntimeException(
294
					"Unexpected failure to set property AbstractThreadGroup.numberOfThreads",
295
					e);
296
		}
297
	}
298
299
	/**
300
	 * <p>
301
	 * Note: Will also set <code>msPerRequest</code> and update the
302
	 * <code>timer</code>.
303
	 * </p>
304
	 *
305
	 * @param throughput
306
	 *            the throughput to set
307
	 */
308
	public void setThroughput(double throughput) {
309
		this.throughput = throughput;
310
		this.msPerRequest = (long) (ConstantThroughputTimer.MILLISEC_PER_MIN / throughput);
311
		timer.setThroughput(throughput);
312
	}
313
314
	/**
315
	 * @param timer
316
	 *            the timer to set
317
	 */
318
	public void setTimer(ConstantThroughputTimer timer) {
319
		this.timer = timer;
320
	}
321
322
	/**
323
	 * @param timerId
324
	 *            the timerId to set
325
	 */
326
	public void setTimerId(String timerId) {
327
		this.timerId = timerId;
328
	}
329
330
	/**
331
	 * {@inheritDoc}
332
	 */
333
	@Override
334
	public String toString() {
335
		StringBuilder builder = new StringBuilder();
336
		builder.append("TestData[");
337
		builder.append("timerId=");
338
		builder.append(timerId);
339
		builder.append(",ConstantThroughputTimer=0x");
340
		builder.append(Integer.toHexString(System.identityHashCode(timer)));
341
		builder.append(",calcMode=");
342
		builder.append(calcMode);
343
		builder.append(",throughput=");
344
		builder.append(throughput);
345
		builder.append(",msPerRequest=");
346
		builder.append(msPerRequest);
347
		builder.append(",threadCount=");
348
		builder.append(jmeterContext.getThreadGroup().getNumberOfThreads());
349
		builder.append(",events=");
350
		builder.append(events.toString());
351
		builder.append("]");
352
353
		return builder.toString();
354
	}
355
356
}
(-)test/src/org/apache/jmeter/timers/simulator_mode4.txt (+81 lines)
Line 0 Link Here
1
#
2
# Constant Throughput Timer Simulator file
3
# See simulator_template.txt for full explanation of files contents.
4
#
5
6
#  calcMode.4=all active threads (shared)
7
# Delay is <code>msPerRequest</code>.
8
# The difference with the simulator in calc mode "all active threads (shared mode)"
9
# is that each thread group will share a single event stream instead of getting a copy of the event stream.
10
# For "all active threads (shared mode)" each timer uses its own delay,
11
# but the calculation is based on when the last thread was run at.
12
# This makes the simulation file trickier to read since all columns need to be considered when calculating the expected delay.
13
# If multiple columns all have values at the same simulation time, then the simulator runs them left to right
14
# Optimal boundaries are not marked as its too complicated - each thread has their own optimal value based on the thread's start time.
15
# It also gets confusing because threads can request a new start time any time before the actual thread start time needed.
16
# Generally, if you are going to use this mode then all timers would use the same msPerRequest.
17
Simulation Time, 1m4t1[5000], 2m4t3[3000], 3m4t5[10000],
18
              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.
19
           1000,            ,            ,             ,  # Subsequent Threads delays are calculated based on the previous time and each thread group shares the event stream.
20
           2000,            ,            ,             ,  # delay = target time <= current time ? 0 : target time - simulation time
21
           3000,            ,            ,             ,  # where target time = previous time + msPerRequest
22
           4000,            ,            ,             ,  # timer 2 : target time = 0 + 3000 = 3000; delay = 3000 - 0 = 3000
23
           5000,            ,            ,             ,  # timer 3 : target time = 3000 + 10000 = 130000; delay = 13000 - 0 = 13000
24
           6000,            ,            ,             ,
25
           7000,            ,            ,      d=16000,  # timer 3 : target time = 13000 + 10000 = 23000; delay = 23000 - 7000 = 16000
26
           8000,            ,            ,             ,
27
           9000,     d=19000,            ,             ,  # timer 1 : target time = 23000 + 5000 = 28000; delay = 28000 - 9000 = 19000
28
          10000,            ,            ,             ,
29
          11000,            ,            ,             ,
30
          12000,            ,            ,             ,
31
          13000,            ,            ,             ,  # 3rd thread start time
32
          14000,            ,            ,             ,
33
          15000,            ,            ,             ,
34
          16000,            ,            ,             ,
35
          17000,            ,            ,             ,
36
          18000,            ,            ,             ,
37
          19000,            ,            ,             ,
38
          20000,            ,            ,             ,
39
          21000,            ,            ,             ,
40
          22000,            ,            ,             ,
41
          23000,            ,            ,             ,  # 4th thread start time
42
          24000,            ,            ,             ,
43
          25000,            ,            ,             ,
44
          26000,            ,            ,             ,
45
          27000,            ,            ,             ,
46
          28000,            ,            ,             ,  # 5th thread start time
47
          29000,            ,            ,             ,
48
          30000,            ,            ,             ,
49
          31000,            ,            ,             ,
50
          32000,            ,            ,             ,
51
          33000,            ,         d=0,             ,  # 6th thread start time, timer 2 : target time = 28000 + 5000 = 33000; delay = 0
52
          34000,            ,      d=2000,             ,  # timer 2 : target time = 33000 + 3000 = 36000; delay = 36000 - 34000 = 2000
53
          35000,            ,            ,             ,
54
          36000,            ,            ,             ,  # 7th thread start time
55
          37000,            ,            ,             ,
56
          38000,            ,            ,       d=8000,  # timer 3 : target time = 36000 + 10000 = 46000; delay = 46000 - 38000 = 8000
57
          39000,            ,            ,             ,
58
          40000,            ,            ,             ,
59
          41000,            ,            ,             ,
60
          42000,            ,            ,             ,
61
          43000,            ,            ,             ,
62
          44000,            ,            ,             ,
63
          45000,            ,            ,             ,
64
          46000,            ,            ,             , # 8th thread start time
65
          47000,            ,            ,             ,
66
          48000,            ,            ,             ,
67
          49000,            ,            ,             ,
68
          50000,            ,            ,             ,
69
          50999,         d=1,            ,             , # timer 1 : target time = 46000 + 5000 = 51000; delay = 51000 - 50999 = 1
70
          51000,            ,            ,             , # 9th thread start time
71
          52000,            ,            ,             ,
72
          53000,            ,            ,             ,
73
          54000,            ,            ,             ,
74
          55000,            ,            ,             ,
75
          56000,            ,            ,             ,
76
          57000,            ,            ,             ,
77
          58000,            ,            ,             ,
78
          59000,            ,            ,             ,
79
          60000,            ,            ,             ,
80
          61000,            ,            ,             ,
81
          61001,            ,            ,          d=0, # timer 3 : target time = 51000 + 10000 = 61000; delay = 0
(-)test/src/org/apache/jmeter/timers/PackageTest.java (-8 / +29 lines)
Lines 32-49 Link Here
32
32
33
    private static final Logger log = LoggingManager.getLoggerForClass();
33
    private static final Logger log = LoggingManager.getLoggerForClass();
34
34
35
    private SimulationClock simulationClock = new SimulationClock();
36
35
    public PackageTest(String arg0) {
37
    public PackageTest(String arg0) {
36
        super(arg0);
38
        super(arg0);
37
    }
39
    }
38
40
41
    @Override
42
    protected void setUp() throws Exception {
43
        super.setUp();
44
        ThroughputInfo.setSystemClock(simulationClock);
45
    }
46
47
    @Override
48
    protected void tearDown() throws Exception {
49
        ThroughputInfo.setSystemClock(new ThroughputInfo.SystemClock());
50
        super.tearDown();
51
    }
52
39
    public void testTimer1() throws Exception {
53
    public void testTimer1() throws Exception {
40
        ConstantThroughputTimer timer = new ConstantThroughputTimer();
54
        ConstantThroughputTimer timer = new ConstantThroughputTimer();
41
        assertEquals(0,timer.getCalcModeInt());// Assume this thread only
55
        assertEquals(0,timer.getCalcModeInt());// Assume this thread only
42
        timer.setThroughput(60.0);// 1 per second
56
        timer.setThroughput(60.0);// 1 per second
43
        long delay = timer.delay(); // Initialise
57
        long delay = timer.delay(); // Initialise
44
        assertEquals(0,delay);
58
        assertEquals(0,delay); // First one runs immediately
45
        Thread.sleep(500);
59
        simulationClock.increaseTime(500);
46
        long diff=Math.abs(timer.delay()-500);
60
        delay = timer.delay();
61
        log.info("testTimer1: new delay = " + delay);
62
        long diff=Math.abs(delay-500);
47
        assertTrue("Delay is approximately 500",diff<=50);
63
        assertTrue("Delay is approximately 500",diff<=50);
48
    }
64
    }
49
65
Lines 51-59 Link Here
51
        ConstantThroughputTimer timer = new ConstantThroughputTimer();
67
        ConstantThroughputTimer timer = new ConstantThroughputTimer();
52
        assertEquals(0,timer.getCalcModeInt());// Assume this thread only
68
        assertEquals(0,timer.getCalcModeInt());// Assume this thread only
53
        timer.setThroughput(60.0);// 1 per second
69
        timer.setThroughput(60.0);// 1 per second
54
        assertEquals(1000,timer.calculateCurrentTarget(0)); // Should delay for 1 second
70
        assertEquals(0, timer.delay()); // First one runs immediately
71
        assertEquals(1000,timer.delay()); // Should delay for 1 second
72
        simulationClock.increaseTime(1000);
55
        timer.setThroughput(60000.0);// 1 per milli-second
73
        timer.setThroughput(60000.0);// 1 per milli-second
56
        assertEquals(1,timer.calculateCurrentTarget(0)); // Should delay for 1 milli-second
74
        assertEquals(1,timer.delay()); // Should delay for 1 milli-second
57
    }
75
    }
58
76
59
    public void testTimer3() throws Exception {
77
    public void testTimer3() throws Exception {
Lines 67-81 Link Here
67
        }
85
        }
68
        assertEquals(10,JMeterContextService.getNumberOfThreads());
86
        assertEquals(10,JMeterContextService.getNumberOfThreads());
69
        timer.setThroughput(600.0);// 10 per second
87
        timer.setThroughput(600.0);// 10 per second
70
        assertEquals(1000,timer.calculateCurrentTarget(0)); // Should delay for 1 second
88
        assertEquals(0, timer.delay()); // First one runs immediately
89
        assertEquals(1000,timer.delay()); // Should delay for 1 second
90
        simulationClock.increaseTime(1000);
71
        timer.setThroughput(600000.0);// 10 per milli-second
91
        timer.setThroughput(600000.0);// 10 per milli-second
72
        assertEquals(1,timer.calculateCurrentTarget(0)); // Should delay for 1 milli-second
92
        assertEquals(1,timer.delay()); // Should delay for 1 milli-second
93
        simulationClock.increaseTime(1);
73
        for(int i=1; i<=990; i++){
94
        for(int i=1; i<=990; i++){
74
            TestJMeterContextService.incrNumberOfThreads();
95
            TestJMeterContextService.incrNumberOfThreads();
75
        }
96
        }
76
        assertEquals(1000,JMeterContextService.getNumberOfThreads());
97
        assertEquals(1000,JMeterContextService.getNumberOfThreads());
77
        timer.setThroughput(60000000.0);// 1000 per milli-second
98
        timer.setThroughput(60000000.0);// 1000 per milli-second
78
        assertEquals(1,timer.calculateCurrentTarget(0)); // Should delay for 1 milli-second
99
        assertEquals(1,timer.delay()); // Should delay for 1 milli-second
79
    }
100
    }
80
101
81
    public void testTimerBSH() throws Exception {
102
    public void testTimerBSH() throws Exception {
(-)test/src/org/apache/jmeter/timers/simulator_mode1.txt (+31 lines)
Line 0 Link Here
1
#
2
# Constant Throughput Timer Simulator file
3
# See simulator_template.txt for full explanation of files contents.
4
#
5
6
#  calcMode.1=this thread only
7
Simulation Time, 1m1t1[5000], 2m1t1[3000], 3m1t2[10000],
8
              0,         d=0,         d=0,          d=0,  # For non-shared Constant Throughput Timers the first request will be at time 0 with no delay.
9
           1000,            ,            ,             ,
10
           2000,            ,            ,             ,
11
           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.
12
           4000,            ,         d=0,             ,  # timer 2 finally finshes, having missed the optimal boundary there is no delay in starting the next request.
13
           5000,           X,            ,             ,
14
           6000,      d=4000,           X,             ,  # timer 1 finishes, there is a delay of 4000ms until the next optimal boundary.
15
           6999,            ,         d=1,             ,  # timer 2 finishes, with 1ms to spare before the next optimal boundary.
16
           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)
17
           8000,            ,            ,             ,
18
           9000,            ,           X,             ,
19
          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
20
          50000,            ,            ,            X,
21
          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
22
          52000,            ,            ,             ,  # Note that Constant Throughput Timer does not average out request times to achieve throughput,
23
          53000,            ,            ,             ,  # if you miss more than one optimal boundary then that time slice is gone forever and will never be caught up.
24
          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
25
          55000,            ,            ,             ,  # but instead will be the difference between now and the next boundary.
26
          56000,            ,            ,             ,  # And the delay is 10000 from the previous time, i.e. 54000 + 10000 = 61000
27
          57000,            ,            ,             ,
28
          58000,            ,            ,             ,
29
          59000,            ,            ,             ,
30
          60000,            ,            ,            X,
31
          61000,            ,            ,             ,
(-)test/src/org/apache/jmeter/timers/ConstantThroughputTimerTest.java (+612 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.timers;
20
21
import java.lang.reflect.Field;
22
import java.util.ArrayList;
23
import java.util.List;
24
25
import org.apache.jmeter.junit.JMeterTestCase;
26
import org.apache.jmeter.threads.JMeterContextService;
27
import org.apache.jorphan.logging.LoggingManager;
28
import org.apache.log.Logger;
29
30
public class ConstantThroughputTimerTest extends JMeterTestCase {
31
32
	private static final Logger LOG = LoggingManager.getLoggerForClass();
33
34
	/**
35
	 * Simulation Clock used to manage "SystemClock" time during tests
36
	 */
37
	private SimulationClock simulationClock;
38
39
	public ConstantThroughputTimerTest(String arg0) {
40
		super(arg0);
41
	}
42
43
	/**
44
	 * <p>
45
	 * This "simulates" which test data has the next event. In order to handle
46
	 * shared mode appropriately the "nextEvent" needs to be moved to the end of
47
	 * the list otherwise the same test data will be returned each time and none
48
	 * of the other "threads" (which sit after this in the list) will get a
49
	 * turn.
50
	 * </p>
51
	 *
52
	 * @param testDataList
53
	 *            the list of test data
54
	 * @return the test data that contains the next event in the simulation, or
55
	 *         null if the are no more events. Non-null next events will be
56
	 *         moved to the end of the <code>List</code>
57
	 */
58
	private ConstantThroughputTimerTestData getNextEvent(
59
			List<ConstantThroughputTimerTestData> testDataList) {
60
61
		ConstantThroughputTimerTestData nextTestData = null;
62
		long nextTestDataEventAt = 0;
63
		for (ConstantThroughputTimerTestData testData : testDataList) {
64
			SimulationEvent simulationEvent = testData.peekFirstEvent();
65
			if (simulationEvent != null) {
66
				if (nextTestData == null
67
						|| simulationEvent.getClockOffset() < nextTestDataEventAt) {
68
					nextTestData = testData;
69
					nextTestDataEventAt = simulationEvent.getClockOffset();
70
				}
71
			}
72
		}
73
		if (nextTestData != null) {
74
			assertTrue("Moving nextTestData to end failed",
75
					testDataList.remove(nextTestData));
76
			assertTrue("Moving nextTestData to end failed",
77
					testDataList.add(nextTestData));
78
		}
79
		return nextTestData;
80
	}
81
82
	/**
83
	 * Run the simulation against the test data list provided.
84
	 *
85
	 * @param testDataList
86
	 *            the test data for the simulation
87
	 * @throws Exception
88
	 *             simulation failures.
89
	 */
90
	private void runSimulation(
91
			List<ConstantThroughputTimerTestData> testDataList)
92
			throws Exception {
93
94
		ConstantThroughputTimerTestData
95
				.setupJMeterContextService_numberOfActiveThreads(testDataList);
96
		LOG.info("Active Thread Count = "
97
				+ JMeterContextService.getNumberOfThreads());
98
99
		testStarted(testDataList);
100
101
		while (true) {
102
			ConstantThroughputTimerTestData nextTestData = getNextEvent(testDataList);
103
			if (nextTestData == null) {
104
				break;
105
			}
106
			nextTestData.activate();
107
108
			SimulationEvent currentEvent = nextTestData.peekFirstEvent();
109
			simulationClock.setOffset(currentEvent.getClockOffset());
110
111
			long expectedDelay = currentEvent.getDelay();
112
113
			LOG.info("Invocation at SimulationClock.offset="
114
					+ simulationClock.getOffset() + " expect delay of "
115
					+ expectedDelay + " for Test " + nextTestData);
116
			long actualDelay = nextTestData.getTimer().delay();
117
			if (actualDelay > 9223300000000000000L) {
118
				/*
119
				 * The above values roughly Double.INFINITY - "current time"
120
				 * failing to call setThroughput causes a division by zero
121
				 * (hence INFINITY) but the delay is based on the time as well
122
				 */
123
				fail("setThroughput() was not called on test data: "
124
						+ nextTestData);
125
			}
126
			assertEquals("Invocation at " + simulationClock.toString()
127
					+ ", for " + nextTestData, expectedDelay, actualDelay);
128
129
			nextTestData.removeFirstEvent();
130
		}
131
132
		testEnded(testDataList);
133
	}
134
135
	/**
136
	 * Sets up the <code>ThroughputInfo.systemClock</code> to be a
137
	 * <code>SimulationClock</code>.
138
	 *
139
	 * @throws Exception
140
	 *             setUp failures
141
	 */
142
	@Override
143
	protected void setUp() throws Exception {
144
		super.setUp();
145
		simulationClock = new SimulationClock();
146
		ThroughputInfo.setSystemClock(simulationClock);
147
148
		ConstantThroughputTimerTestData
149
				.setupJMeterContextService_threadContext();
150
	}
151
152
	/**
153
	 * Resets the <code>ThroughputInfo.systemClock</code> to
154
	 * <code>ThroughputInfo.SystemClock</code>
155
	 *
156
	 * @throws Exception
157
	 *             tearDown failures
158
	 */
159
	@Override
160
	protected void tearDown() throws Exception {
161
		ThroughputInfo.setSystemClock(new ThroughputInfo.SystemClock());
162
		super.tearDown();
163
	}
164
165
	/**
166
	 * Mode 1 "This Thead Only", In this test threads take
167
	 * <code>msPerRequest</code> to complete. i.e. on the optimal boundaries.
168
	 *
169
	 * @throws Exception
170
	 *             test failures
171
	 */
172
	public void testDelayMode1ThisThreadOnly() throws Exception {
173
		LOG.info("testDelayMode1ThisThreadOnly");
174
175
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
176
		testData.setThroughput(12.0);
177
		testData.setNumberOfThreadsInThreadGroup(1);
178
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_1);
179
180
		testData.addEvent(new SimulationEvent(0, 0));
181
		testData.addEvent(new SimulationEvent(5000, 0));
182
		testData.addEvent(new SimulationEvent(10000, 0));
183
		testData.addEvent(new SimulationEvent(15000, 0));
184
		testData.addEvent(new SimulationEvent(20000, 0));
185
		testData.addEvent(new SimulationEvent(25000, 0));
186
		testData.addEvent(new SimulationEvent(30000, 0));
187
		testData.addEvent(new SimulationEvent(35000, 0));
188
		testData.addEvent(new SimulationEvent(40000, 0));
189
		testData.addEvent(new SimulationEvent(45000, 0));
190
		testData.addEvent(new SimulationEvent(50000, 0));
191
		testData.addEvent(new SimulationEvent(55000, 0));
192
		testData.addEvent(new SimulationEvent(60000, 0));
193
194
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
195
		simulation.add(testData);
196
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
197
198
		runSimulation(simulation);
199
	}
200
201
	/**
202
	 * Mode 2 "All Active Threads", the delay is
203
	 * <code>msPerRequest * AllActiveThread Count</code>.
204
	 *
205
	 * @throws Exception
206
	 *             test failures
207
	 */
208
	public void testDelayMode2AllActiveThreads_ManyThreads() throws Exception {
209
		LOG.info("testDelayMode2AllActiveThreads_ManyThreads");
210
211
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
212
		testData.setThroughput(12.0);
213
		testData.setNumberOfThreadsInThreadGroup(200);
214
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_2);
215
216
		testData.addEvent(new SimulationEvent(0, 0));
217
		testData.addEvent(new SimulationEvent(5000 * 200 * 1, 0));
218
		testData.addEvent(new SimulationEvent(5000 * 200 * 2, 0));
219
		testData.addEvent(new SimulationEvent(5000 * 200 * 3, 0));
220
		testData.addEvent(new SimulationEvent(5000 * 200 * 4, 0));
221
		testData.addEvent(new SimulationEvent(5000 * 200 * 5, 0));
222
223
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
224
		simulation.add(testData);
225
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
226
227
		runSimulation(simulation);
228
	}
229
230
	/**
231
	 * Mode 2 "All Active Threads", the delay is
232
	 * <code>msPerRequest * AllActiveThread Count</code>, for one thread is the
233
	 * same as Mode 1.
234
	 *
235
	 * @throws Exception
236
	 *             test failures
237
	 */
238
	public void testDelayMode2AllActiveThreads_OneThread() throws Exception {
239
		LOG.info("testDelayMode2AllActiveThreads_OneThread");
240
241
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
242
		testData.setThroughput(12.0);
243
		testData.setNumberOfThreadsInThreadGroup(1);
244
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_2);
245
246
		testData.addEvent(new SimulationEvent(0, 0));
247
		testData.addEvent(new SimulationEvent(5000, 0));
248
		testData.addEvent(new SimulationEvent(10000, 0));
249
		testData.addEvent(new SimulationEvent(15000, 0));
250
		testData.addEvent(new SimulationEvent(20000, 0));
251
		testData.addEvent(new SimulationEvent(25000, 0));
252
		testData.addEvent(new SimulationEvent(30000, 0));
253
		testData.addEvent(new SimulationEvent(35000, 0));
254
		testData.addEvent(new SimulationEvent(40000, 0));
255
		testData.addEvent(new SimulationEvent(45000, 0));
256
		testData.addEvent(new SimulationEvent(50000, 0));
257
		testData.addEvent(new SimulationEvent(55000, 0));
258
		testData.addEvent(new SimulationEvent(60000, 0));
259
260
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
261
		simulation.add(testData);
262
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
263
264
		runSimulation(simulation);
265
	}
266
267
	/**
268
	 * Mode 2 "All Active Threads", the delay is
269
	 * <code>msPerRequest * AllActiveThread Count</code>.
270
	 *
271
	 * @throws Exception
272
	 *             test failures
273
	 */
274
	public void testDelayMode2AllActiveThreads_TwoThreads() throws Exception {
275
		LOG.info("testDelayMode2AllActiveThreads_TwoThreads");
276
277
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
278
		testData.setThroughput(12.0);
279
		testData.setNumberOfThreadsInThreadGroup(2);
280
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_2);
281
282
		testData.addEvent(new SimulationEvent(0, 0));
283
		testData.addEvent(new SimulationEvent(10000, 0));
284
		testData.addEvent(new SimulationEvent(20000, 0));
285
		testData.addEvent(new SimulationEvent(30000, 0));
286
		testData.addEvent(new SimulationEvent(40000, 0));
287
		testData.addEvent(new SimulationEvent(50000, 0));
288
		testData.addEvent(new SimulationEvent(60000, 0));
289
290
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
291
		simulation.add(testData);
292
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
293
294
		runSimulation(simulation);
295
	}
296
297
	/**
298
	 * Mode 3 "All Active Threads in Thread Group", the delay is
299
	 * <code>msPerRequest * active ThreadsInThreadGroup Count</code>.
300
	 *
301
	 * @throws Exception
302
	 *             test failures
303
	 */
304
	public void testDelayMode3AllActiveThreadsInThreadGroup_ManyThreads()
305
			throws Exception {
306
		LOG.info("testDelayMode3AllActiveThreadsInThreadGroup_ManyThreads");
307
308
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
309
		testData.setThroughput(12.0);
310
		testData.setNumberOfThreadsInThreadGroup(200);
311
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_3);
312
313
		testData.addEvent(new SimulationEvent(0, 0));
314
		testData.addEvent(new SimulationEvent(5000 * 200 * 1, 0));
315
		testData.addEvent(new SimulationEvent(5000 * 200 * 2, 0));
316
		testData.addEvent(new SimulationEvent(5000 * 200 * 3, 0));
317
		testData.addEvent(new SimulationEvent(5000 * 200 * 4, 0));
318
		testData.addEvent(new SimulationEvent(5000 * 200 * 5, 0));
319
320
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
321
		simulation.add(testData);
322
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
323
324
		runSimulation(simulation);
325
	}
326
327
	/**
328
	 * Mode 3 "All Active Threads in Thread Group", the delay is
329
	 * <code>msPerRequest * ThreadsInThreadGroup Count</code>. For 1 Thread this
330
	 * is the same as Mode 1.
331
	 *
332
	 * @throws Exception
333
	 *             test failures
334
	 */
335
	public void testDelayMode3AllActiveThreadsInThreadGroup_OneThread()
336
			throws Exception {
337
		LOG.info("testDelayMode3AllActiveThreadsInThreadGroup_OneThread");
338
339
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
340
		testData.setThroughput(12.0);
341
		testData.setNumberOfThreadsInThreadGroup(1);
342
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_3);
343
344
		testData.addEvent(new SimulationEvent(0, 0));
345
		testData.addEvent(new SimulationEvent(5000, 0));
346
		testData.addEvent(new SimulationEvent(10000, 0));
347
		testData.addEvent(new SimulationEvent(15000, 0));
348
		testData.addEvent(new SimulationEvent(20000, 0));
349
		testData.addEvent(new SimulationEvent(25000, 0));
350
		testData.addEvent(new SimulationEvent(30000, 0));
351
		testData.addEvent(new SimulationEvent(35000, 0));
352
		testData.addEvent(new SimulationEvent(40000, 0));
353
		testData.addEvent(new SimulationEvent(45000, 0));
354
		testData.addEvent(new SimulationEvent(50000, 0));
355
		testData.addEvent(new SimulationEvent(55000, 0));
356
		testData.addEvent(new SimulationEvent(60000, 0));
357
358
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
359
		simulation.add(testData);
360
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
361
362
		runSimulation(simulation);
363
	}
364
365
	/**
366
	 * Mode 3 "All Active Threads in Thread Group", the delay is
367
	 * <code>msPerRequest * ThreadsInThreadGroup Count</code>.
368
	 *
369
	 * @throws Exception
370
	 *             test failures
371
	 */
372
	public void testDelayMode3AllActiveThreadsInThreadGroup_TwoThreads()
373
			throws Exception {
374
		LOG.info("testDelayMode3AllActiveThreadsInThreadGroup_TwoThreads");
375
376
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
377
		testData.setThroughput(12.0);
378
		testData.setNumberOfThreadsInThreadGroup(2);
379
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_3);
380
381
		testData.addEvent(new SimulationEvent(0, 0));
382
		testData.addEvent(new SimulationEvent(10000, 0));
383
		testData.addEvent(new SimulationEvent(20000, 0));
384
		testData.addEvent(new SimulationEvent(30000, 0));
385
		testData.addEvent(new SimulationEvent(40000, 0));
386
		testData.addEvent(new SimulationEvent(50000, 0));
387
		testData.addEvent(new SimulationEvent(60000, 0));
388
389
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
390
		simulation.add(testData);
391
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
392
393
		runSimulation(simulation);
394
	}
395
396
	/**
397
	 * Mode 4 "All Active Threads (Shared)", the delay is a constant
398
	 * <code>msPerRequest</code> but each thread shares the
399
	 * <code>previousTime</code> a request was invoked.
400
	 *
401
	 * @throws Exception
402
	 *             test failures
403
	 */
404
	public void testDelayMode4AllActiveThreadsShared_OneThread()
405
			throws Exception {
406
		LOG.info("testDelayMode4AllActiveThreadsShared");
407
408
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
409
		testData.setThroughput(12.0);
410
		testData.setNumberOfThreadsInThreadGroup(1);
411
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_4);
412
413
		testData.addEvent(new SimulationEvent(0, 0));
414
		testData.addEvent(new SimulationEvent(5000, 0));
415
		testData.addEvent(new SimulationEvent(10000, 0));
416
		testData.addEvent(new SimulationEvent(15000, 0));
417
		testData.addEvent(new SimulationEvent(20000, 0));
418
		testData.addEvent(new SimulationEvent(25000, 0));
419
		testData.addEvent(new SimulationEvent(30000, 0));
420
		testData.addEvent(new SimulationEvent(35000, 0));
421
		testData.addEvent(new SimulationEvent(40000, 0));
422
		testData.addEvent(new SimulationEvent(45000, 0));
423
		testData.addEvent(new SimulationEvent(50000, 0));
424
		testData.addEvent(new SimulationEvent(55000, 0));
425
		testData.addEvent(new SimulationEvent(60000, 0));
426
427
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
428
		simulation.add(testData);
429
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
430
431
		runSimulation(simulation);
432
	}
433
434
	/**
435
	 * Mode 5 "All Active Threads In Thread Group(Shared)", the delay is a
436
	 * constant <code>msPerRequest</code> but each thread in the thread group
437
	 * shares the <code>previousTime</code> a request was invoked.
438
	 *
439
	 * @throws Exception
440
	 *             test failures
441
	 */
442
	public void testDelayMode5AllActiveThreadsInThreadGroupShared_OneThread()
443
			throws Exception {
444
		LOG.info("testDelayMode5AllActiveThreadsInThreadGroupShared");
445
446
		ConstantThroughputTimerTestData testData = new ConstantThroughputTimerTestData();
447
		testData.setThroughput(12.0);
448
		testData.setNumberOfThreadsInThreadGroup(1);
449
		testData.setCalcMode(ConstantThroughputTimerTestData.CALC_MODE_5);
450
451
		testData.addEvent(new SimulationEvent(0, 0));
452
		testData.addEvent(new SimulationEvent(5000, 0));
453
		testData.addEvent(new SimulationEvent(10000, 0));
454
		testData.addEvent(new SimulationEvent(15000, 0));
455
		testData.addEvent(new SimulationEvent(20000, 0));
456
		testData.addEvent(new SimulationEvent(25000, 0));
457
		testData.addEvent(new SimulationEvent(30000, 0));
458
		testData.addEvent(new SimulationEvent(35000, 0));
459
		testData.addEvent(new SimulationEvent(40000, 0));
460
		testData.addEvent(new SimulationEvent(45000, 0));
461
		testData.addEvent(new SimulationEvent(50000, 0));
462
		testData.addEvent(new SimulationEvent(55000, 0));
463
		testData.addEvent(new SimulationEvent(60000, 0));
464
465
		List<ConstantThroughputTimerTestData> simulation = new ArrayList<ConstantThroughputTimerTestData>();
466
		simulation.add(testData);
467
		ConstantThroughputTimerTestData.createAdditionalThreads(simulation);
468
469
		runSimulation(simulation);
470
	}
471
472
	/**
473
	 * Notify all the timers in the list of test data that the tests have ended.
474
	 *
475
	 * @param testDataList
476
	 *            varargs list of test data to notify
477
	 */
478
	private void testEnded(List<ConstantThroughputTimerTestData> testDataList) {
479
		for (ConstantThroughputTimerTestData testData : testDataList) {
480
			testData.getTimer().testEnded();
481
		}
482
	}
483
484
	/**
485
	 * Test Mode 1 timers from simulation file simulator_mode1.txt
486
	 *
487
	 * @throws Exception
488
	 *             test failures
489
	 */
490
	public void testMode1Timers() throws Exception {
491
		ConstantThroughPutTimerSimulation simulation = new ConstantThroughPutTimerSimulation();
492
		List<ConstantThroughputTimerTestData> testDataList = simulation
493
				.loadSimulationFile("org/apache/jmeter/timers/simulator_mode1.txt");
494
495
		runSimulation(testDataList);
496
	}
497
498
	/**
499
	 * Test Mode 2 timers from simulation file simulator_mode2.txt
500
	 *
501
	 * @throws Exception
502
	 *             test failures
503
	 */
504
	public void testMode2Timers() throws Exception {
505
		ConstantThroughPutTimerSimulation simulation = new ConstantThroughPutTimerSimulation();
506
		List<ConstantThroughputTimerTestData> testDataList = simulation
507
				.loadSimulationFile("org/apache/jmeter/timers/simulator_mode2.txt");
508
509
		runSimulation(testDataList);
510
	}
511
512
	/**
513
	 * Test Mode 3 timers from simulation file simulator_mode3.txt
514
	 *
515
	 * @throws Exception
516
	 *             test failures
517
	 */
518
	public void testMode3Timers() throws Exception {
519
		ConstantThroughPutTimerSimulation simulation = new ConstantThroughPutTimerSimulation();
520
		List<ConstantThroughputTimerTestData> testDataList = simulation
521
				.loadSimulationFile("org/apache/jmeter/timers/simulator_mode3.txt");
522
523
		runSimulation(testDataList);
524
	}
525
526
	/**
527
	 * Test Mode 4 timers from simulation file simulator_mode4.txt
528
	 *
529
	 * @throws Exception
530
	 *             test failures
531
	 */
532
	public void testMode4Timers() throws Exception {
533
		ConstantThroughPutTimerSimulation simulation = new ConstantThroughPutTimerSimulation();
534
		List<ConstantThroughputTimerTestData> testDataList = simulation
535
				.loadSimulationFile("org/apache/jmeter/timers/simulator_mode4.txt");
536
537
		runSimulation(testDataList);
538
	}
539
540
	/**
541
	 * Test Mode 5 timers from simulation file simulator_mode5.txt
542
	 *
543
	 * @throws Exception
544
	 *             test failures
545
	 */
546
	public void testMode5Timers() throws Exception {
547
		ConstantThroughPutTimerSimulation simulation = new ConstantThroughPutTimerSimulation();
548
		List<ConstantThroughputTimerTestData> testDataList = simulation
549
				.loadSimulationFile("org/apache/jmeter/timers/simulator_mode5.txt");
550
551
		runSimulation(testDataList);
552
	}
553
554
	/**
555
	 * Notify all the timers in the list of test data that the tests are
556
	 * starting.
557
	 *
558
	 * @param testDataList
559
	 *            list of test data to notify
560
	 */
561
	private void testStarted(List<ConstantThroughputTimerTestData> testDataList) {
562
		for (ConstantThroughputTimerTestData testData : testDataList) {
563
			testData.activate();
564
			testData.getTimer().testStarted();
565
		}
566
	}
567
}
568
569
/**
570
 * JMeter depends on commons-lang:2.4. These methods are copied from 2.5
571
 *
572
 * TODO: Delete when dependency upgraded.
573
 */
574
class Copy_Commons_Lang_2_5_Reflect {
575
	public static Field getDeclaredField(Class<?> cls, String fieldName,
576
			boolean forceAccess) {
577
		if (cls == null) {
578
			throw new IllegalArgumentException("The class must not be null");
579
		}
580
		if (fieldName == null) {
581
			throw new IllegalArgumentException(
582
					"The field name must not be null");
583
		}
584
		try {
585
			// only consider the specified class by using getDeclaredField()
586
			Field field = cls.getDeclaredField(fieldName);
587
			field.setAccessible(true);
588
			return field;
589
		} catch (NoSuchFieldException e) {
590
		}
591
		return null;
592
	}
593
594
	public static void writeDeclaredStaticField(Class<?> cls, String fieldName,
595
			Object value, boolean forceAccess) throws IllegalAccessException {
596
		Field field = getDeclaredField(cls, fieldName, forceAccess);
597
		if (field == null) {
598
			throw new IllegalArgumentException("Cannot locate declared field "
599
					+ cls.getName() + "." + fieldName);
600
		}
601
		// already forced access above, don't repeat it here:
602
		writeField(field, (Object) null, value, false);
603
	}
604
605
	public static void writeField(Field field, Object target, Object value,
606
			boolean forceAccess) throws IllegalAccessException {
607
		if (field == null) {
608
			throw new IllegalArgumentException("The field must not be null");
609
		}
610
		field.set(target, value);
611
	}
612
}
(-)test/src/org/apache/jmeter/timers/simulator_mode5.txt (+58 lines)
Line 0 Link Here
1
#
2
# Constant Throughput Timer Simulator file
3
# See simulator_template.txt for full explanation of files contents.
4
#
5
6
#  calcMode.5=all active threads in current thread group (shared)
7
# Delay is <code>msPerRequest</code>.
8
# The difference with the simulator in calc mode "all active threads in current thread group (shared)"
9
# is that each thread group will get a single event stream shared amongst the threads in the thread group,
10
# instead of each thread getting a copy of the event stream.
11
# For "all active threads in current thread group (shared)" each timer uses its own delay,
12
# but the calculation is based on when the last thread within the thread group was run at.
13
14
# delay = target time <= current time ? 0 : target time - simulation time
15
#   where target time = previous time + msPerRequest
16
Simulation Time, 1m5t1[5000], 2m5t3[3000], 3m5t5[10000],
17
              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.
18
           1000,            ,            ,             ,  # Subsequent Threads delays are calculated based on the previous time and each thread in the thread group shares the event stream.
19
           2000,            ,      d=1000,             ,  # timer 2 : target time = 0 + 3000 = 3000; delay = 3000 - 2000 = 1000
20
           3000,            ,           X,             ,
21
           4000,      d=1000,            ,             ,  # timer 1 : target time = 0 + 5000 = 5000; delay = 5000 - 4000 = 1000
22
           5000,           X,            ,             ,
23
           6000,            ,         d=0,             ,  # timer 2 : target time = 3000 + 3000 = 6000; delay = 0
24
           7000,            ,            ,       d=3000,  # timer 3 : target time = 0 + 10000 = 10000; delay = 10000 - 7000 = 3000
25
           8000,            ,            ,             ,
26
           9000,            ,           X,             ,
27
          10000,           X,         d=0,            X,  # timer 2 : target time = 6000 + 3000 = 9000; delay = 0
28
          11000,         d=0,      d=2000,             ,  # timer 2 : target time = 10000 + 3000 = 13000; delay = 13000 - 11000 = 2000
29
          12000,            ,           X,             ,
30
          13000,            ,      d=3000,             ,  # timer 2 : target time = 13000 + 3000 = 16000; delay = 16000 - 13000 = 3000
31
          14000,            ,            ,             ,
32
          15000,           X,           X,             ,
33
          16000,            ,            ,       d=4000,  # timer 3 : target time = 10000 + 10000 = 20000; delay = 20000 - 16000 = 4000
34
          17000,            ,            ,             ,
35
          18000,            ,           X,      d=12000,  # timer 3 : target time = 20000 + 10000 = 30000; delay = 30000 - 18000 = 12000
36
          19000,            ,            ,             ,
37
          20000,           X,            ,            X,
38
          21000,            ,           X,             ,
39
          22000,            ,            ,             ,
40
          23000,            ,            ,             ,
41
          24000,            ,           X,             ,
42
          25000,           X,            ,             ,
43
          26000,            ,            ,             ,
44
          27000,            ,           X,             ,
45
          28000,            ,            ,             ,
46
          29000,            ,            ,             ,
47
          30000,           X,           X,            X,
48
          31000,            ,            ,             ,
49
          32000,            ,            ,             ,
50
          33000,            ,            ,             ,
51
          34000,            ,            ,             ,
52
          35000,            ,            ,             ,
53
          36000,            ,            ,             ,
54
          37000,            ,            ,             ,
55
          38000,            ,            ,             ,
56
          39000,            ,            ,             ,
57
          40000,            ,            ,            X,
58
          41000,            ,            ,          d=0,  # timer 3 : target time = 30000 + 10000 = 40000; delay = 0
(-)test/src/org/apache/jmeter/timers/SimulationClock.java (+130 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
package org.apache.jmeter.timers;
19
20
import org.apache.jorphan.logging.LoggingManager;
21
import org.apache.log.Logger;
22
23
/**
24
 * A Simluation Clock used in unit testing instead of java.lang.System
25
 */
26
public class SimulationClock extends ThroughputInfo.SystemClock {
27
28
	private static final Logger LOG = LoggingManager.getLoggerForClass();
29
30
	/**
31
	 * <p>
32
	 * See {@link ThroughputInfo#calculateDelay(long)}.
33
	 * </p>
34
	 * This needs to be set to something larger than the first delay expected.
35
	 * Setting to Jan 1 2000 0:00
36
	 */
37
	private long intialTime = 946647000000L;
38
39
	/**
40
	 * When was the current time last logged, so that the it is only logged when
41
	 * the time changes.
42
	 */
43
	private long lastLoggedCurrentTime = 0L;
44
45
	/**
46
	 * The offset from the initial time.
47
	 */
48
	private long offset = 0L;
49
50
	/**
51
	 * @return <code>initialTime + offset</code>
52
	 */
53
	@Override
54
	public long getCurrentTime() {
55
		logTime();
56
		return getCurrentTimeInternal();
57
	}
58
59
	/**
60
	 * @return the current time used internally by other code.
61
	 */
62
	private long getCurrentTimeInternal() {
63
		return intialTime + offset;
64
	}
65
66
	/**
67
	 * @return the offset
68
	 */
69
	public long getOffset() {
70
		return offset;
71
	}
72
73
	/**
74
	 * @param increment
75
	 *            the amount in milliseconds to increment the simulation clock
76
	 *            by
77
	 */
78
	public void increaseTime(long increment) {
79
		if (increment < 0) {
80
			throw new IllegalStateException(
81
					"Negative increments are not allowed");
82
		}
83
		offset += increment;
84
		logTime();
85
	}
86
87
	/**
88
	 * Log the time, but only if it hasn't changed since the last time it was
89
	 * logged.
90
	 */
91
	private void logTime() {
92
		long currentTime = getCurrentTimeInternal();
93
		if (lastLoggedCurrentTime != currentTime) {
94
			LOG.info(toString());
95
			lastLoggedCurrentTime = currentTime;
96
		}
97
	}
98
99
	/**
100
	 * {@inheritDoc}
101
	 */
102
	@Override
103
	public String toString() {
104
		return "Offset = " + offset;
105
	}
106
107
	/**
108
	 * @param initialTime
109
	 *            new initial simulation time
110
	 */
111
	public void setInitialTime(long initialTime) {
112
		this.intialTime = initialTime;
113
		logTime();
114
	}
115
116
	/**
117
	 * @param offset
118
	 *            the offset to set
119
	 */
120
	public void setOffset(long offset) {
121
		if (offset < this.offset) {
122
			throw new IllegalStateException("Offset (" + offset
123
					+ ") must be larger than the current offset )"
124
					+ this.offset + ".");
125
		}
126
		this.offset = offset;
127
		logTime();
128
	}
129
130
}
(-)test/src/org/apache/jmeter/timers/simulator_template.txt (+75 lines)
Line 0 Link Here
1
#
2
# Constant Throughput Timer Simulator template file
3
#
4
# Lines starting with # are comments and ignored.
5
# Lines can also include # and the rest of the line is considered a comment.
6
#
7
# The first line is the Timer declarations.
8
# The first line's column is ignored as this is the header name for the clock time
9
# Each other column is of the form
10
#   <n>'m'<m>'t'<t>'['<msPerRequest']'
11
# where
12
#   n = the id of the timer
13
#   m = mode number (See Available Modes below)
14
#   t = number of threads in the ThreadGroup the Constant Throughput Timer belongs to
15
#   msPerRequest = the milliseconds per request this Timer is optimally trying to hit
16
#    (it's easier to think in milliseconds per request than throughput)
17
#    You can convert between the two with the following formula:
18
#       msPerRequest = 60000 / throughput
19
# e.g.
20
#   1[5000] (Timer id 1, with a 5000 milliseconds per request)
21
#
22
# Each subsequent line is a simluation clock event.
23
# The first column is the elapsed time in milliseconds since the start of the simulation.
24
# Each other column is of the form
25
#   d=<delay> | 'X'
26
# where
27
#   delay = the delay in milliseconds expected when this timer requests
28
#			to be scheduled again by the Constant Throughput Timer.
29
#           i.e. All the previous time the Sampler was busy sending its Request
30
#   'X' = a marker that shows where the optimal time for this timer would be.
31
#         Not used at all, just a visual marker for people reading the files.
32
# e.g.
33
#  d=0 (A delay of zero, used when the next request happens after a millisecond per request length,
34
#       or if it hits the optimal time boundary)
35
#
36
# If a row does not have any d= values then it has no effect on the simulation.
37
# These are included to make it easier for people reading the files.
38
39
# Available Modes
40
#  calcMode.1=this thread only
41
#  calcMode.2=all active threads
42
#  calcMode.3=all active threads in current thread group
43
#  calcMode.4=all active threads (shared)
44
#  calcMode.5=all active threads in current thread group (shared)
45
46
# Assumptions:
47
#  * There is only one Constant Throughput Timer per ThreadGroup (Having more than one probably doesn't work the way you think it will)
48
49
# delay = target time <= current time ? 0 : target time - simulation time
50
#   where target time = previous time + msPerRequest
51
Simulation Time, 1m1t1[5000], 2m1t1[3000], 3m1t2[10000],
52
              0,         d=0,         d=0,          d=0,  # For non-shared Constant Throughput Timers the first request will be at time 0 with no delay.
53
           1000,            ,            ,             ,  # The choice of time increments is up to you, and there is no need to keep them uniform.
54
           2000,            ,            ,             ,
55
           3000,      d=2000,           X,             ,  # Here timer 1's request has completed, so there is a delay of 2000ms (target time = 0 + 5000 = 5000; delay = 5000 - 3000 = 2000) until the next optimal request boundary.  It is also timer 2's optimal boundary, but it has been missed this time.
56
           4000,            ,         d=0,             ,  # timer 2 finally finshes, having missed the optimal boundary there is no delay (target time = 0 + 3000 = 3000; delay = 0) in starting the next request.
57
           5000,           X,            ,             ,
58
           6000,      d=4000,           X,             ,  # timer 1 : target time = 5000 + 5000 = 10000; delay = 10000 - 6000 = 4000
59
           6999,            ,         d=1,             ,  # timer 2 finishes, with 1ms to spare before the next optimal boundary. : target time = 4000 + 3000 = 7000; delay = 7000 - 6999 = 1
60
           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)
61
           8000,            ,            ,             ,
62
           9000,            ,            ,             ,
63
          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
64
          50000,            ,            ,            X,
65
          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
66
          52000,            ,            ,             ,  # Note that Constant Throughput Timer does not average out request times to achieve throughput,
67
          53000,            ,            ,             ,  # if you miss more than one optimal boundary then that time slice is gone forever and will never be caught up.
68
          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
69
          55000,            ,            ,             ,  # but instead will be the difference between now and the next boundary.
70
          56000,            ,            ,             ,  # And the delay is 7000 : target time = 51000 + 10000 = 61000; delay = 61000 - 54000 = 7000
71
          57000,            ,            ,             ,
72
          58000,            ,            ,             ,
73
          59000,            ,            ,             ,
74
          60000,            ,            ,            X,
75
          61000,            ,            ,             ,
(-)test/src/org/apache/jmeter/timers/simulator_mode2.txt (+31 lines)
Line 0 Link Here
1
#
2
# Constant Throughput Timer Simulator file
3
# See simulator_template.txt for full explanation of files contents.
4
#
5
6
#  calcMode.2=all active threads
7
# Total Active threads in this simulation = 1 + 3 + 5 = 9
8
# Delay is <code>msPerRequest * AllActiveThread Count</code>.
9
# Timer 1 delay = 5000 * 9 = 45,000
10
# Timer 2 delay = 3000 * 9 = 27,000
11
# Timer 3 delay = 10000 * 9 = 90,000
12
13
# delay = target time <= current time ? 0 : target time - simulation time
14
#   where target time = previous time + msPerRequest
15
Simulation Time, 1m2t1[5000], 2m2t3[3000], 3m2t5[10000],
16
              0,         d=0,         d=0,          d=0,  # For non-shared Constant Throughput Timers the first request will be at time 0 with no delay.
17
           4000,            ,     d=23000,             ,  # timer 2 : target time = 0 + 27000 = 270000; delay = 27000 - 4000 = 23000
18
           5000,     d=40000,            ,             ,  # timer 1 : target time = 0 + 45000 = 45000; delay = 45000 - 5000 = 40000
19
          27000,            ,           X,             ,
20
          30000,            ,     d=24000,             ,  # timer 2 : target time = 27000 + 27000 = 54000; delay = 54000 - 30000 = 24000
21
          45000,           X,            ,             ,
22
          54000,            ,           X,             ,
23
          70000,            ,            ,      d=20000,  # timer 3 : target time = 0 + 90000 = 90000; delay = 90000 - 70000 = 20000
24
          81000,            ,           X,             ,
25
          90000,           X,            ,            X,
26
         108000,            ,           X,             ,
27
         135000,           X,            ,             ,
28
         180000,           X,            ,            X,
29
         269500,            ,            ,          d=0,  # timer 3 : target time = 90000 + 90000 = 180000; delay = 0
30
         270000,           X,            ,            X,
31
(-)test/src/org/apache/jmeter/timers/SimulationEvent.java (+62 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
package org.apache.jmeter.timers;
19
20
/**
21
 * <p>
22
 * A Simulation Event for <code>ConstantThroughputTimer</code>.
23
 * </p>
24
 * <p>
25
 * Events happen at the specified <code>clockOffset</code> and expect that the
26
 * <code>ConstantThroughputTimer</code> will have a delay of <code>delay</code>.
27
 * </p>
28
 */
29
public class SimulationEvent {
30
	private int clockOffset;
31
	private int delay;
32
33
	public SimulationEvent(int clockOffset, int delay) {
34
		this.clockOffset = clockOffset;
35
		this.delay = delay;
36
	}
37
38
	/**
39
	 * @return the clockOffset the events occurs on
40
	 */
41
	public int getClockOffset() {
42
		return clockOffset;
43
	}
44
45
	/**
46
	 * @return the delay expected by the <code>ConstantThroughputTimer</code>
47
	 *         when calculating the next time an event will occur
48
	 */
49
	public int getDelay() {
50
		return delay;
51
	}
52
53
	/**
54
	 * {@inheritDoc}
55
	 */
56
	@Override
57
	public String toString() {
58
		return "SimulationEvent [clockOffset=" + clockOffset + ", delay="
59
				+ delay + "]";
60
	}
61
62
}
(-)test/src/org/apache/jmeter/threads/MockJMeterContext.java (+242 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
package org.apache.jmeter.threads;
19
20
import org.apache.jmeter.engine.StandardJMeterEngine;
21
import org.apache.jmeter.samplers.SampleResult;
22
import org.apache.jmeter.samplers.Sampler;
23
24
/**
25
 * <p>
26
 * A Mock implementation of <code>JMeterContext</code>
27
 * </p>
28
 * <p>
29
 * The normal way of obtaining <code>JMeterContext</code> is via
30
 * {@link JMeterContextService#getContext()} which relies on
31
 * <code>ThreadLocal</code> variables. In unit tests setting up threads is
32
 * difficult. This Mock allows you to "swap out" what should be returned during
33
 * your unit tests so that one thread can be used to run the tests. Setting the
34
 * <code>delegate</code> allows you to do the "swap out"
35
 * </p>
36
 *
37
 */
38
public class MockJMeterContext extends JMeterContext {
39
40
	private JMeterContext delegate;
41
42
	/**
43
	 * @return Factory method for creating <code>JMeterContext</code> since its
44
	 *         visibility is "default" and not available outside of this
45
	 *         package.
46
	 */
47
	public static JMeterContext newJMeterContext() {
48
		return new JMeterContext();
49
	}
50
51
	/**
52
	 * @return the delegate
53
	 */
54
	public JMeterContext getDelegate() {
55
		return delegate;
56
	}
57
58
	/**
59
	 * @param delegate
60
	 *            the delegate to set
61
	 */
62
	public void setDelegate(JMeterContext delegate) {
63
		this.delegate = delegate;
64
	}
65
66
	/**
67
	 * @return
68
	 * @see java.lang.Object#hashCode()
69
	 */
70
	public int hashCode() {
71
		return delegate.hashCode();
72
	}
73
74
	/**
75
	 *
76
	 * @see org.apache.jmeter.threads.JMeterContext#clear()
77
	 */
78
	public void clear() {
79
		delegate.clear();
80
	}
81
82
	/**
83
	 * @return
84
	 * @see org.apache.jmeter.threads.JMeterContext#getVariables()
85
	 */
86
	public JMeterVariables getVariables() {
87
		return delegate.getVariables();
88
	}
89
90
	/**
91
	 * @return
92
	 * @see org.apache.jmeter.threads.JMeterContext#getReadBuffer()
93
	 */
94
	public byte[] getReadBuffer() {
95
		return delegate.getReadBuffer();
96
	}
97
98
	/**
99
	 * @param vars
100
	 * @see org.apache.jmeter.threads.JMeterContext#setVariables(org.apache.jmeter.threads.JMeterVariables)
101
	 */
102
	public void setVariables(JMeterVariables vars) {
103
		delegate.setVariables(vars);
104
	}
105
106
	/**
107
	 * @return
108
	 * @see org.apache.jmeter.threads.JMeterContext#getPreviousResult()
109
	 */
110
	public SampleResult getPreviousResult() {
111
		return delegate.getPreviousResult();
112
	}
113
114
	/**
115
	 * @param result
116
	 * @see org.apache.jmeter.threads.JMeterContext#setPreviousResult(org.apache.jmeter.samplers.SampleResult)
117
	 */
118
	public void setPreviousResult(SampleResult result) {
119
		delegate.setPreviousResult(result);
120
	}
121
122
	/**
123
	 * @return
124
	 * @see org.apache.jmeter.threads.JMeterContext#getCurrentSampler()
125
	 */
126
	public Sampler getCurrentSampler() {
127
		return delegate.getCurrentSampler();
128
	}
129
130
	/**
131
	 * @param sampler
132
	 * @see org.apache.jmeter.threads.JMeterContext#setCurrentSampler(org.apache.jmeter.samplers.Sampler)
133
	 */
134
	public void setCurrentSampler(Sampler sampler) {
135
		delegate.setCurrentSampler(sampler);
136
	}
137
138
	/**
139
	 * @return
140
	 * @see org.apache.jmeter.threads.JMeterContext#getPreviousSampler()
141
	 */
142
	public Sampler getPreviousSampler() {
143
		return delegate.getPreviousSampler();
144
	}
145
146
	/**
147
	 * @return
148
	 * @see org.apache.jmeter.threads.JMeterContext#getThreadNum()
149
	 */
150
	public int getThreadNum() {
151
		return delegate.getThreadNum();
152
	}
153
154
	/**
155
	 * @param threadNum
156
	 * @see org.apache.jmeter.threads.JMeterContext#setThreadNum(int)
157
	 */
158
	public void setThreadNum(int threadNum) {
159
		delegate.setThreadNum(threadNum);
160
	}
161
162
	/**
163
	 * @return
164
	 * @see org.apache.jmeter.threads.JMeterContext#getThread()
165
	 */
166
	public JMeterThread getThread() {
167
		return delegate.getThread();
168
	}
169
170
	/**
171
	 * @param obj
172
	 * @return
173
	 * @see java.lang.Object#equals(java.lang.Object)
174
	 */
175
	public boolean equals(Object obj) {
176
		return delegate.equals(obj);
177
	}
178
179
	/**
180
	 * @param thread
181
	 * @see org.apache.jmeter.threads.JMeterContext#setThread(org.apache.jmeter.threads.JMeterThread)
182
	 */
183
	public void setThread(JMeterThread thread) {
184
		delegate.setThread(thread);
185
	}
186
187
	/**
188
	 * @return
189
	 * @see org.apache.jmeter.threads.JMeterContext#getThreadGroup()
190
	 */
191
	public AbstractThreadGroup getThreadGroup() {
192
		return delegate.getThreadGroup();
193
	}
194
195
	/**
196
	 * @param threadgrp
197
	 * @see org.apache.jmeter.threads.JMeterContext#setThreadGroup(org.apache.jmeter.threads.AbstractThreadGroup)
198
	 */
199
	public void setThreadGroup(AbstractThreadGroup threadgrp) {
200
		delegate.setThreadGroup(threadgrp);
201
	}
202
203
	/**
204
	 * @return
205
	 * @see org.apache.jmeter.threads.JMeterContext#getEngine()
206
	 */
207
	public StandardJMeterEngine getEngine() {
208
		return delegate.getEngine();
209
	}
210
211
	/**
212
	 * @param engine
213
	 * @see org.apache.jmeter.threads.JMeterContext#setEngine(org.apache.jmeter.engine.StandardJMeterEngine)
214
	 */
215
	public void setEngine(StandardJMeterEngine engine) {
216
		delegate.setEngine(engine);
217
	}
218
219
	/**
220
	 * @return
221
	 * @see org.apache.jmeter.threads.JMeterContext#isSamplingStarted()
222
	 */
223
	public boolean isSamplingStarted() {
224
		return delegate.isSamplingStarted();
225
	}
226
227
	/**
228
	 * @param b
229
	 * @see org.apache.jmeter.threads.JMeterContext#setSamplingStarted(boolean)
230
	 */
231
	public void setSamplingStarted(boolean b) {
232
		delegate.setSamplingStarted(b);
233
	}
234
235
	/**
236
	 * @return
237
	 * @see java.lang.Object#toString()
238
	 */
239
	public String toString() {
240
		return delegate.toString();
241
	}
242
}

Return to bug 51480