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.compliance.timer;
023:
024: import junit.framework.TestCase;
025:
026: import java.util.ArrayList;
027: import java.util.Date;
028:
029: import javax.management.MBeanServer;
030: import javax.management.MBeanServerFactory;
031: import javax.management.Notification;
032: import javax.management.NotificationListener;
033: import javax.management.ObjectName;
034: import javax.management.timer.TimerNotification;
035:
036: /**
037: * Basic timer test.<p>
038: *
039: * The aim of these tests is to check the most common uses of the timer
040: * service.
041: *
042: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
043: */
044: public class TimerTest extends TestCase implements NotificationListener {
045: /**
046: * The period for a timer notification. This needs to be small so the tests * don't take too long. * The wait needs to be long enough to be sure the monitor has enough time * to send the notification and switch the context to the handler. */
047: public static final long PERIOD = 100;
048: public static final long WAIT = 10000;
049: /**
050: * The number of repeats for occurances tests */
051: public static final long REPEATS = 2;
052:
053: // Attributes ----------------------------------------------------------------
054:
055: /**
056: * The object name of the timer service
057: */
058: ObjectName timerName;
059:
060: /**
061: * The MBean server
062: */
063: MBeanServer server;
064:
065: /**
066: * The received notifications
067: */
068: ArrayList receivedNotifications = new ArrayList();
069:
070: // Constructor ---------------------------------------------------------------
071:
072: public TimerTest(String s) {
073: super (s);
074: }
075:
076: // Tests ---------------------------------------------------------------------
077:
078: /**
079: * Test a single notification works.
080: */
081: public void testSingleNotification() throws Exception {
082: try {
083: startTimerService();
084:
085: Integer id = addNotification("test", "hello", "data",
086: calcTime(PERIOD), 0, 1);
087: expectNotifications(1);
088:
089: // TODO
090: // if (getNotificationType(id) != null)
091: // fail("Single notification still registered");
092: } finally {
093: stopTimerService();
094: }
095: }
096:
097: /**
098: * Test a repeated notification works.
099: */
100: public void testRepeatedNotification() throws Exception {
101: try {
102: startTimerService();
103: Integer id = addNotification("test", "hello", "data",
104: calcTime(PERIOD), PERIOD, REPEATS);
105: expectNotifications(1);
106: expectNotifications(2);
107:
108: // TODO
109: // if (getNotificationType(id) != null)
110: // fail("Repeated notification still registered");
111: } finally {
112: stopTimerService();
113: }
114: }
115:
116: /**
117: * Test infinite notification works.
118: */
119: public void testInfiniteNotification() throws Exception {
120: try {
121: startTimerService();
122:
123: Integer id = addNotification("test", "hello", "data",
124: calcTime(PERIOD), PERIOD, 0);
125: expectNotifications(1);
126: expectNotifications(2);
127:
128: if (getNotificationType(id) == null)
129: fail("Infinite notification not registered");
130: } finally {
131: stopTimerService();
132: }
133: }
134:
135: /**
136: * Test two infinite notification works.
137: */
138: public void testTwoNotificationProducers() throws Exception {
139: try {
140: startTimerService();
141: long lTimeOne = 5 * 1000;
142: long lTimeTwo = 12 * 1000;
143: long lWait = 2 * lTimeTwo;
144: long lStart = calcTime(lTimeOne);
145: Integer lIdOne = addNotification("test-2", "hello", "data",
146: lStart + lTimeOne, lTimeOne, 0);
147: Integer lIdTwo = addNotification("test-2", "hello", "data",
148: lStart + lTimeTwo, lTimeTwo, 0);
149:
150: expectNotifications(1, lWait);
151: expectNotifications(2, lWait);
152: // Check time differences which should be around TIME ONE
153: TimerNotification lNotificationOne = (TimerNotification) receivedNotifications
154: .get(0);
155: TimerNotification lNotificationTwo = (TimerNotification) receivedNotifications
156: .get(1);
157: checkNotificationID(lNotificationOne, lIdOne);
158: checkNotificationID(lNotificationTwo, lIdOne);
159: checkTimeDifference(lNotificationOne, lNotificationTwo,
160: lTimeOne);
161:
162: expectNotifications(3, lWait);
163: lNotificationOne = lNotificationTwo;
164: lNotificationTwo = (TimerNotification) receivedNotifications
165: .get(2);
166: checkNotificationID(lNotificationTwo, lIdTwo);
167: checkTimeDifference(lNotificationOne, lNotificationTwo,
168: (lTimeTwo - (2 * lTimeOne)));
169:
170: expectNotifications(4, lWait);
171: lNotificationOne = lNotificationTwo;
172: lNotificationTwo = (TimerNotification) receivedNotifications
173: .get(3);
174: checkNotificationID(lNotificationTwo, lIdOne);
175: checkTimeDifference(lNotificationOne, lNotificationTwo,
176: ((3 * lTimeOne) - lTimeTwo));
177:
178: expectNotifications(5, lWait);
179: lNotificationOne = lNotificationTwo;
180: lNotificationTwo = (TimerNotification) receivedNotifications
181: .get(4);
182: checkNotificationID(lNotificationTwo, lIdOne);
183: checkTimeDifference(lNotificationOne, lNotificationTwo,
184: lTimeOne);
185:
186: expectNotifications(6, lWait);
187: lNotificationOne = lNotificationTwo;
188: lNotificationTwo = (TimerNotification) receivedNotifications
189: .get(5);
190: checkNotificationID(lNotificationTwo, lIdTwo);
191: checkTimeDifference(lNotificationOne, lNotificationTwo,
192: ((2 * lTimeTwo) - (4 * lTimeOne)));
193: } finally {
194: stopTimerService();
195: }
196: }
197:
198: // Support functions ---------------------------------------------------------
199:
200: /**
201: * Get an MBeanServer, install the timer service and a notification
202: * listener.
203: */
204: private void startTimerService() throws Exception {
205: server = MBeanServerFactory.createMBeanServer("Timer");
206:
207: timerName = new ObjectName("Timer:type=TimerService");
208: server.createMBean("javax.management.timer.Timer", timerName,
209: new Object[0], new String[0]);
210: server.invoke(timerName, "start", new Object[0], new String[0]);
211:
212: receivedNotifications.clear();
213: server.addNotificationListener(timerName, this , null, null);
214: }
215:
216: /**
217: * Remove everything used by this test. Cannot report failures because
218: * the test might have failed earlier. All notifications are removed,
219: * the RI hangs otherwise.
220: */
221: private void stopTimerService() {
222: try {
223: server.invoke(timerName, "removeAllNotifications",
224: new Object[0], new String[0]);
225: server.invoke(timerName, "stop", new Object[0],
226: new String[0]);
227: server.unregisterMBean(timerName);
228: MBeanServerFactory.releaseMBeanServer(server);
229: } catch (Exception ignored) {
230: }
231: }
232:
233: /**
234: * Handle a notification, just add it to the list
235: *
236: * @param notification the notification received
237: * @param handback not used
238: */
239: public void handleNotification(Notification notification,
240: Object handback) {
241: synchronized (receivedNotifications) {
242: receivedNotifications.add(notification);
243: receivedNotifications.notifyAll();
244: }
245: }
246:
247: /**
248: * Wait for the timer notification and see if we have the correct number
249: * hopefully this should synchronize this test with the timer thread.
250: *
251: * @param expected the number of notifications expected
252: * @throws Exception when the notifications are incorrect
253: */
254: public void expectNotifications(int expected) throws Exception {
255: expectNotifications(expected, WAIT);
256: }
257:
258: /**
259: * Wait for the timer notification and see if we have the correct number
260: * hopefully this should synchronize this test with the timer thread.
261: *
262: * @param expected the number of notifications expected
263: * @param wait time in milli seconds to wait for the notification
264: * @throws Exception when the notifications are incorrect
265: */
266: public void expectNotifications(int expected, long wait)
267: throws Exception {
268: synchronized (receivedNotifications) {
269: if (receivedNotifications.size() > expected)
270: fail("too many notifications");
271: if (receivedNotifications.size() < expected) {
272: receivedNotifications.wait(wait);
273: }
274: assertEquals(expected, receivedNotifications.size());
275: }
276: }
277:
278: /**
279: * Checks if the given Notification ID is the same as the
280: * one of the given Notification
281: *
282: * @param pNotification Notification to be tested
283: * @param pNotificationID Id the Notification should have
284: **/
285: public void checkNotificationID(TimerNotification pNotification,
286: Integer pNotificationID) {
287: if (pNotification == null) {
288: fail("Notification is null");
289: }
290: if (!pNotification.getNotificationID().equals(pNotificationID)) {
291: fail("Wrong Notification ID received: "
292: + pNotification.getNotificationID()
293: + ", expected: " + pNotificationID);
294: }
295: }
296:
297: /**
298: * Checks if the time between the two Notification is in a
299: * +- 10% limit
300: *
301: * @param pNotificationOne First Notification to be tested
302: * @param pNotificationTwo Second Notification to be tested
303: * @param pTimeDiffernce Expected Time Difference
304: **/
305: public void checkTimeDifference(TimerNotification pNotificationOne,
306: TimerNotification pNotificationTwo, long pTimeDiffernce) {
307: long lDiff = pNotificationTwo.getTimeStamp()
308: - pNotificationOne.getTimeStamp();
309: if (lDiff < (pTimeDiffernce - (pTimeDiffernce / 10))
310: || lDiff > (pTimeDiffernce + (pTimeDiffernce / 10))) {
311: fail("Time between first two notification is too small or too big: "
312: + pTimeDiffernce);
313: }
314: }
315:
316: /**
317: * Add a timer notification
318: *
319: * @param type the type of the notification
320: * @param message the message
321: * @param data the user data
322: * @param time the time of the notification
323: * @param period the period of notification
324: * @param occurs the number of occurances
325: * @return the id of the notfication
326: */
327: private Integer addNotification(String type, String message,
328: String data, long time, long period, long occurs)
329: throws Exception {
330: return (Integer) server.invoke(timerName, "addNotification",
331: new Object[] { type, message, data, new Date(time),
332: new Long(period), new Long(occurs) },
333: new String[] { "java.lang.String", "java.lang.String",
334: "java.lang.Object", "java.util.Date", "long",
335: "long" });
336: }
337:
338: /**
339: * Get the notification type for an id
340: *
341: * @param id the id of the notification
342: * @return the type of the notification
343: */
344: private String getNotificationType(Integer id) throws Exception {
345: // This is called after the last expected notification
346: // The timer thread has notified us, but hasn't had time
347: // to remove the notification, give it chance, before
348: // checking for correct behaviour.
349: Thread.yield();
350:
351: return (String) server.invoke(timerName, "getNotificationType",
352: new Object[] { id },
353: new String[] { "java.lang.Integer" });
354: }
355:
356: /**
357: * Calculate the time using an offset from the current time.
358: * @param offset the offset from the current time
359: * @return the calculated time
360: */
361: private long calcTime(long offset) {
362: return System.currentTimeMillis() + offset;
363: }
364: }
|