001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package test.stress.timer;
023:
024: import java.util.Date;
025: import java.util.Random;
026:
027: import javax.management.MBeanServer;
028: import javax.management.MBeanServerFactory;
029: import javax.management.Notification;
030: import javax.management.NotificationListener;
031: import javax.management.ObjectName;
032: import javax.management.timer.Timer;
033:
034: import junit.framework.TestCase;
035:
036: /**
037: * Timer Stress Tests
038: *
039: * This test works by starting a lot of notifications at the start and
040: * checks the concurrency by performing lots of operations.<p>
041: *
042: * It then waits for the slow notifications to complete allowing any lag
043: * due to slower computers to be caught up with.<p>
044: *
045: * Any concurrency problem or dropped notifications should show up
046: * when the test times out and the target notifications are not reached.
047: *
048: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
049: */
050: public class TimerTestCase extends TestCase implements
051: NotificationListener {
052: // Constants ---------------------------------------------------------------
053:
054: String TIMER_TYPE = "TimerType";
055: String MESSAGE = "Message";
056: String USER_DATA = "UserData";
057:
058: // Attributes --------------------------------------------------------------
059:
060: /**
061: * The MBeanServer
062: */
063: MBeanServer server;
064:
065: /**
066: * The object name of the timer
067: */
068: ObjectName timerName;
069:
070: /**
071: * The timer
072: */
073: Timer timer;
074:
075: /**
076: * The number of notifications
077: */
078: int notifications = 0;
079:
080: /**
081: * The target notifications
082: */
083: int target = 0;
084:
085: /**
086: * The percentage done
087: */
088: int nextPercentage = 10;
089:
090: // Constructor -------------------------------------------------------------
091:
092: /**
093: * Construct the test
094: */
095: public TimerTestCase(String s) {
096: super (s);
097: }
098:
099: // Tests -------------------------------------------------------------------
100:
101: /**
102: * Test the timer under stress conditions
103: */
104: public void testTortureOne() throws Exception {
105: target = TimerSUITE.TIMERS * TimerSUITE.NOTIFICATIONS;
106: System.err.println("Timer Torture One: target=" + target);
107:
108: initTest();
109: try {
110: initTimer();
111: startTimer();
112:
113: // Start lots of timer notifications
114: nextPercentage = 10;
115: Random random = new Random();
116: for (int i = 0; i < TimerSUITE.TIMERS; i++) {
117: addNotification(TimerSUITE.OFFSET, random
118: .nextInt(TimerSUITE.PERIOD),
119: TimerSUITE.NOTIFICATIONS);
120: }
121:
122: // Perform some operations
123: for (int k = 0; k < target; k++) {
124: Integer id = addNotification(Timer.ONE_HOUR,
125: Timer.ONE_HOUR, 1);
126: timer.getAllNotificationIDs();
127: timer.getDate(id);
128: timer.getNbNotifications();
129: ;
130: timer.getNbOccurences(id);
131: timer.getNotificationIDs(TIMER_TYPE);
132: timer.getNotificationUserData(id);
133: timer.getPeriod(id);
134: timer.getSendPastNotifications();
135: timer.isActive();
136: timer.isEmpty();
137: timer.setSendPastNotifications(true);
138: removeNotification(id);
139: }
140:
141: // Give it time to complete but check for stalled
142: for (int j = 0; j < TimerSUITE.NOTIFICATIONS; j++) {
143: if (notifications >= target)
144: break;
145: int lastNotifications = notifications;
146: sleep(TimerSUITE.PERIOD * 10);
147: if (lastNotifications == notifications) {
148: sleep(TimerSUITE.PERIOD * 10);
149: if (lastNotifications == notifications)
150: break;
151: }
152: }
153:
154: // Test the number of notifications
155: assertTrue(notifications == target);
156: } finally {
157: endTest();
158: }
159: }
160:
161: // Support -----------------------------------------------------------------
162:
163: /**
164: * Start a new test
165: */
166: private void initTest() {
167: notifications = 0;
168: server = MBeanServerFactory.createMBeanServer();
169: }
170:
171: /**
172: * End the test
173: */
174: private void endTest() throws Exception {
175: server.removeNotificationListener(timerName, this );
176: stopTimer();
177: MBeanServerFactory.releaseMBeanServer(server);
178: }
179:
180: /**
181: * Create a timer and register ourselves as a listener
182: */
183: private void initTimer() {
184: try {
185: timer = new Timer();
186: timerName = new ObjectName("test:type=timer");
187: server.registerMBean(timer, timerName);
188: server.addNotificationListener(timerName, this , null, null);
189: } catch (Exception e) {
190: fail(e.toString());
191: }
192: }
193:
194: /**
195: * Start the timer
196: */
197: private void startTimer() {
198: timer.start();
199: }
200:
201: /**
202: * Stop the timer, does a small wait to avoid problems with the RI
203: */
204: private void stopTimer() {
205: timer.removeAllNotifications();
206: timer.stop();
207: }
208:
209: /**
210: * Add a notification
211: */
212: private Integer addNotification(long offset, long period,
213: long occurs) {
214: return timer.addNotification(TIMER_TYPE, MESSAGE, USER_DATA,
215: timeOffset(offset), period, occurs);
216: }
217:
218: /**
219: * Remove a notification
220: */
221: private void removeNotification(Integer id) throws Exception {
222: timer.removeNotification(id);
223: }
224:
225: /**
226: * Handle the notification, just add it to the list
227: */
228: public synchronized void handleNotification(Notification n,
229: Object ignored) {
230: notifications++;
231: float percentage = 100 * notifications / target;
232: if (percentage >= nextPercentage) {
233: System.err.println("Done " + nextPercentage + "%");
234: nextPercentage += 10;
235: }
236: }
237:
238: /**
239: * Get the time using and offset
240: */
241: private Date timeOffset(long offset) {
242: return new Date(System.currentTimeMillis() + offset);
243: }
244:
245: /**
246: * Sleep for a bit
247: */
248: private void sleep(long time) {
249: try {
250: Thread.sleep(time);
251: } catch (InterruptedException ignored) {
252: }
253: }
254: }
|