~ubuntu-branches/debian/squeeze/junitperf/squeeze

« back to all changes in this revision

Viewing changes to src/app/com/clarkware/junitperf/LoadTest.java

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Vandyck
  • Date: 2006-11-06 12:10:29 UTC
  • mfrom: (3.1.3 edgy)
  • Revision ID: james.westby@ubuntu.com-20061106121029-0f8e7pzmig6sh1x5
Tags: 1.9.1-5
* built with java-gcj-compat-dev.
* debian/rules: 
  + removed ant-launcher.jar
  + removed the test target (closes: #396419)
* Standards-Version: 3.7.2 (no change)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package com.clarkware.junitperf;
2
 
 
3
 
import junit.framework.Test;
4
 
import junit.framework.TestResult;
5
 
import junit.extensions.RepeatedTest;
6
 
 
7
 
/**
8
 
 * The <code>LoadTest</code> is a test decorator that runs
9
 
 * a test with a simulated number of concurrent users and
10
 
 * iterations.
11
 
 * <p>
12
 
 * In its simplest form, a <code>LoadTest</code> is constructed 
13
 
 * with a test to decorate and the number of concurrent users.
14
 
 * </p>
15
 
 * <p>
16
 
 * For example, to create a load test of 10 concurrent users
17
 
 * with each user running <code>ExampleTest</code> once and 
18
 
 * all users started simultaneously, use:
19
 
 * <blockquote>
20
 
 * <pre>
21
 
 * Test loadTest = new LoadTest(new TestSuite(ExampleTest.class), 10);
22
 
 * </pre>
23
 
 * </blockquote>
24
 
 * or, to load test a single test method, use: 
25
 
 * <blockquote>
26
 
 * <pre>
27
 
 * Test loadTest = new LoadTest(new ExampleTest("testSomething"), 10);
28
 
 * </pre>
29
 
 * </blockquote>
30
 
 * </p>
31
 
 * <p>
32
 
 * The load can be ramped by specifying a pluggable 
33
 
 * <code>Timer</code> instance which prescribes the delay
34
 
 * between the addition of each concurrent user.  A
35
 
 * <code>ConstantTimer</code> has a constant delay, with 
36
 
 * a zero value indicating that all users will be started 
37
 
 * simultaneously. A <code>RandomTimer</code> has a random 
38
 
 * delay with a uniformly distributed variation.
39
 
 * </p>
40
 
 * <p>
41
 
 * For example, to create a load test of 10 concurrent users
42
 
 * with each user running <code>ExampleTest.testSomething()</code> once and 
43
 
 * with a one second delay between the addition of users, use:
44
 
 * <blockquote>
45
 
 * <pre>
46
 
 * Timer timer = new ConstantTimer(1000);
47
 
 * Test loadTest = new LoadTest(new ExampleTest("testSomething"), 10, timer);
48
 
 * </pre>
49
 
 * </blockquote>
50
 
 * </p>
51
 
 * <p>
52
 
 * In order to simulate each concurrent user running a test for a 
53
 
 * specified number of iterations, a <code>LoadTest</code> can be 
54
 
 * constructed to decorate a <code>RepeatedTest</code>. 
55
 
 * Alternatively, a <code>LoadTest</code> convenience constructor 
56
 
 * specifying the number of iterations is provided which creates a 
57
 
 * <code>RepeatedTest</code>. 
58
 
 * </p>
59
 
 * <p>
60
 
 * For example, to create a load test of 10 concurrent users
61
 
 * with each user running <code>ExampleTest.testSomething()</code> for 20 iterations, 
62
 
 * and with a one second delay between the addition of users, use:
63
 
 * <blockquote>
64
 
 * <pre>
65
 
 * Timer timer = new ConstantTimer(1000);
66
 
 * Test repeatedTest = new RepeatedTest(new ExampleTest("testSomething"), 20);
67
 
 * Test loadTest = new LoadTest(repeatedTest, 10, timer);
68
 
 * </pre>
69
 
 * </blockquote>
70
 
 * or, alternatively, use: 
71
 
 * <blockquote>
72
 
 * <pre>
73
 
 * Timer timer = new ConstantTimer(1000);
74
 
 * Test loadTest = new LoadTest(new ExampleTest("testSomething"), 10, 20, timer);
75
 
 * </pre>
76
 
 * </blockquote> 
77
 
 * A <code>LoadTest</code> can be decorated as a <code>TimedTest</code>
78
 
 * to test the elapsed time of the load test.  For example, to decorate 
79
 
 * the load test constructed above as a timed test with a maximum elapsed 
80
 
 * time of 2 seconds, use:
81
 
 * <blockquote>
82
 
 * <pre>
83
 
 * Test timedTest = new TimedTest(loadTest, 2000);
84
 
 * </pre>
85
 
 * </blockquote>
86
 
 * </p>
87
 
 * <p>
88
 
 * By default, a <code>LoadTest</code> does not enforce test 
89
 
 * atomicity (as defined in transaction processing) if its decorated 
90
 
 * test spawns threads, either directly or indirectly.  In other words, 
91
 
 * if a decorated test spawns a thread and then returns control without 
92
 
 * waiting for its spawned thread to complete, then the test is assumed 
93
 
 * to be transactionally complete.  
94
 
 * </p>
95
 
 * <p>
96
 
 * If threads are integral to the successful completion of 
97
 
 * a decorated test, meaning that the decorated test should not be 
98
 
 * treated as complete until all of its threads complete, then  
99
 
 * <code>setEnforceTestAtomicity(true)</code> should be invoked to 
100
 
 * enforce test atomicity.  This effectively causes the load test to 
101
 
 * wait for the completion of all threads belonging to the same 
102
 
 * <code>ThreadGroup</code> as the thread running the decorated test.
103
 
 * </p>
104
 
 * @author <a href="mailto:mike@clarkware.com">Mike Clark</a>
105
 
 * @author <a href="http://www.clarkware.com">Clarkware Consulting, Inc.</a>
106
 
 * @author Ervin Varga
107
 
 *
108
 
 * @see junit.framework.Test
109
 
 */
110
 
 
111
 
public class LoadTest implements Test {
112
 
 
113
 
        private final int _users;
114
 
        private final Timer _timer;
115
 
        private final ThreadedTest _test;
116
 
        private final ThreadedTestGroup _group;
117
 
        private final ThreadBarrier _barrier;
118
 
        private boolean _enforceTestAtomicity;
119
 
 
120
 
        /**
121
 
         * Constructs a <code>LoadTest</code> to decorate 
122
 
         * the specified test using the specified number 
123
 
         * of concurrent users starting simultaneously.
124
 
         *
125
 
         * @param test Test to decorate.
126
 
         * @param users Number of concurrent users.
127
 
         */
128
 
        public LoadTest(Test test, int users) {
129
 
                this(test, users, new ConstantTimer(0));
130
 
        }
131
 
        
132
 
        /**
133
 
         * Constructs a <code>LoadTest</code> to decorate 
134
 
         * the specified test using the specified number 
135
 
         * of concurrent users starting simultaneously and
136
 
         * the number of iterations per user.
137
 
         *
138
 
         * @param test Test to decorate.
139
 
         * @param users Number of concurrent users.
140
 
         * @param iteration Number of iterations per user.
141
 
         */
142
 
        public LoadTest(Test test, int users, int iterations) {
143
 
                this(test, users, iterations, new ConstantTimer(0));
144
 
        }
145
 
                
146
 
        /**
147
 
         * Constructs a <code>LoadTest</code> to decorate 
148
 
         * the specified test using the specified number 
149
 
         * of concurrent users, number of iterations per
150
 
         * user, and delay timer.
151
 
         *
152
 
         * @param test Test to decorate.
153
 
         * @param users Number of concurrent users.
154
 
         * @param iteration Number of iterations per user.
155
 
         * @param timer Delay timer.
156
 
         */
157
 
        public LoadTest(Test test, int users, int iterations, Timer timer) {
158
 
                this(new RepeatedTest(test, iterations), users, timer);
159
 
        }
160
 
        
161
 
        /**
162
 
         * Constructs a <code>LoadTest</code> to decorate 
163
 
         * the specified test using the specified number 
164
 
         * of concurrent users and delay timer.
165
 
         *
166
 
         * @param test Test to decorate.
167
 
         * @param users Number of concurrent users.
168
 
         * @param timer Delay timer.
169
 
         */
170
 
        public LoadTest(Test test, int users, Timer timer) {
171
 
        
172
 
                 if (users < 1) {
173
 
            throw new IllegalArgumentException("Number of users must be > 0");
174
 
        } else if (timer == null) {
175
 
            throw new IllegalArgumentException("Delay timer is null");
176
 
        } else if (test == null) {
177
 
            throw new IllegalArgumentException("Decorated test is null");
178
 
        }
179
 
                 
180
 
                _users = users;
181
 
                _timer = timer;
182
 
                setEnforceTestAtomicity(false);
183
 
                _barrier = new ThreadBarrier(users);
184
 
                _group = new ThreadedTestGroup(this);
185
 
                _test = new ThreadedTest(test, _group, _barrier);
186
 
        }
187
 
        
188
 
        /**
189
 
         * Indicates whether test atomicity should be enforced.
190
 
         * <p>
191
 
         * If threads are integral to the successful completion of 
192
 
         * a decorated test, meaning that the decorated test should not be 
193
 
         * treated as complete until all of its threads complete, then  
194
 
         * <code>setEnforceTestAtomicity(true)</code> should be invoked to 
195
 
         * enforce test atomicity.  This effectively causes the load test to 
196
 
         * wait for the completion of all threads belonging to the same 
197
 
         * <code>ThreadGroup</code> as the thread running the decorated test.
198
 
         * 
199
 
         * @param isAtomic <code>true</code> to enforce test atomicity;
200
 
         *                 <code>false</code> otherwise.
201
 
         */
202
 
        public void setEnforceTestAtomicity(boolean isAtomic) {
203
 
                _enforceTestAtomicity = isAtomic;
204
 
        }
205
 
        
206
 
        /**
207
 
         * Returns the number of tests in this load test.
208
 
         *
209
 
         * @return Number of tests.
210
 
         */
211
 
        public int countTestCases() {
212
 
                return _test.countTestCases() * _users;
213
 
        }
214
 
 
215
 
        /**
216
 
         * Runs the test.
217
 
         *
218
 
         * @param result Test result.
219
 
         */
220
 
        public void run(TestResult result) {
221
 
        
222
 
                _group.setTestResult(result);
223
 
 
224
 
                for (int i=0; i < _users; i++) {
225
 
 
226
 
                        if (result.shouldStop()) {
227
 
                                _barrier.cancelThreads(_users - i);
228
 
                                break;
229
 
                        }
230
 
 
231
 
                        _test.run(result);
232
 
 
233
 
                        try {
234
 
 
235
 
                                Thread.sleep(getDelay());
236
 
 
237
 
                        } catch(InterruptedException ignored) {}
238
 
                }
239
 
                
240
 
                waitForTestCompletion();
241
 
 
242
 
                cleanup();
243
 
        }
244
 
        
245
 
        protected void waitForTestCompletion() {
246
 
                //
247
 
                // TODO: May require a strategy pattern
248
 
                //       if other algorithms emerge.
249
 
                // 
250
 
                if (_enforceTestAtomicity) {
251
 
                        waitForAllThreadsToComplete();
252
 
                } else {
253
 
                        waitForThreadedTestThreadsToComplete();
254
 
                }
255
 
        }
256
 
 
257
 
        protected void waitForThreadedTestThreadsToComplete() {
258
 
                
259
 
                while (!_barrier.isReached()) {
260
 
                        sleep(50);
261
 
                }
262
 
        }
263
 
        
264
 
        protected void waitForAllThreadsToComplete() {
265
 
                
266
 
                while (_group.activeCount() > 0) {
267
 
                        sleep(50);
268
 
                }
269
 
        }
270
 
        
271
 
        protected void sleep(long time)  {
272
 
                try { 
273
 
                        
274
 
                        Thread.sleep(time); 
275
 
                        
276
 
                } catch(Exception ignored) { } 
277
 
        }
278
 
        
279
 
        protected void cleanup() {
280
 
                try {
281
 
                
282
 
                        _group.destroy();
283
 
                
284
 
                } catch (Throwable ignored) { }
285
 
        }
286
 
        
287
 
        public String toString() {
288
 
                if (_enforceTestAtomicity) {
289
 
                        return "LoadTest (ATOMIC): " + _test.toString();
290
 
                } else {
291
 
                        return "LoadTest (NON-ATOMIC): " + _test.toString();
292
 
                }
293
 
        }
294
 
 
295
 
        protected long getDelay() {
296
 
                return _timer.getDelay();
297
 
        }
298
 
}