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