~ubuntu-branches/ubuntu/natty/junitperf/natty

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Takashi Okamoto
  • Date: 2003-05-03 13:51:04 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20030503135104-g65uwm06z7rebnb1
Tags: 1.8-1
* New upstream release.
* close wishlist for ver1.8.(closes:#191565)

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