001: package org.jgroups.tests;
002:
003: import junit.framework.Test;
004: import junit.framework.TestCase;
005: import junit.framework.TestSuite;
006: import org.jgroups.TimeoutException;
007: import org.jgroups.stack.Interval;
008: import org.jgroups.util.Promise;
009: import org.jgroups.util.TimeScheduler;
010: import org.jgroups.util.Util;
011:
012: import java.util.HashMap;
013:
014: /**
015: * Test cases for TimeScheduler
016: *
017: * @author Bela Ban
018: * @version $Id: TimeSchedulerTest.java,v 1.9.2.1 2007/04/27 06:26:39 belaban Exp $
019: */
020: public class TimeSchedulerTest extends TestCase {
021: TimeScheduler timer = null;
022: static final int NUM_MSGS = 1000;
023: long[] xmit_timeouts = { 1000, 2000, 4000, 8000 };
024: double PERCENTAGE_OFF = 0.3; // how much can expected xmit_timeout and real timeout differ to still be okay ?
025: HashMap msgs = new HashMap(); // keys=seqnos (Long), values=Entries
026:
027: public TimeSchedulerTest(String name) {
028: super (name);
029: }
030:
031: public void setUp() throws Exception {
032: super .setUp();
033: timer = new TimeScheduler();
034: }
035:
036: public void tearDown() throws Exception {
037: super .tearDown();
038: try {
039: timer.stop();
040: timer.cancel();
041: timer = null;
042: } catch (InterruptedException e) {
043: }
044: }
045:
046: public void testCancel() {
047: for (int i = 0; i < 10; i++)
048: timer.add(new OneTimeTask(1000));
049: assertEquals(10, timer.size());
050: timer.cancel();
051: assertEquals(0, timer.size());
052: }
053:
054: public void testTaskCancellationBeforeTaskHasRun() {
055: StressTask task = new StressTask();
056: timer.add(task);
057: assertEquals(1, timer.size());
058: task.cancel();
059: assertEquals(1, timer.size());
060:
061: Util.sleep(200);
062: int num_executions = task.getNum_executions();
063: System.out.println("number of task executions="
064: + num_executions);
065: assertEquals(
066: "task should never have executed as it was cancelled before execution",
067: 0, num_executions);
068:
069: timer.purge(); // removes cancelled tasks
070: assertEquals(0, timer.size());
071: }
072:
073: public void testTaskCancellationAfterHasRun() {
074: StressTask task = new StressTask();
075: timer.add(task);
076: assertEquals(1, timer.size());
077:
078: Util.sleep(200); // wait until task has executed
079: task.cancel();
080: assertEquals(1, timer.size());
081:
082: int num_executions = task.getNum_executions();
083: System.out.println("number of task executions="
084: + num_executions);
085: assertTrue(
086: "task should have executed at least 1 time, as it was cancelled after 200ms",
087: num_executions >= 1);
088: Util.sleep(60); // wait until the task is run again and is then cancelled
089: timer.purge(); // removes cancelled tasks
090: assertEquals(0, timer.size());
091: }
092:
093: public void testImmediateExecution() {
094: Promise p = new Promise();
095: ImmediateTask task = new ImmediateTask(p);
096: timer.add(task);
097: try {
098: long start = System.currentTimeMillis(), stop;
099: p.getResultWithTimeout(5);
100: stop = System.currentTimeMillis();
101: System.out.println("task took " + (stop - start) + "ms");
102: } catch (TimeoutException e) {
103: fail("ran into timeout - task should have executed immediately");
104: }
105: }
106:
107: public void testStress() {
108: StressTask t;
109:
110: for (int i = 0; i < 1000; i++) {
111: for (int j = 0; j < 1000; j++) {
112: t = new StressTask();
113: timer.add(t);
114: t.cancel();
115: }
116: System.out.println(i + ": " + timer.size());
117: }
118: for (int i = 0; i < 10; i++) {
119: System.out.println(timer.size());
120: Util.sleep(500);
121: }
122: }
123:
124: public void test2Tasks() {
125: int size;
126:
127: System.out.println("timer: " + timer);
128:
129: System.out
130: .println(System.currentTimeMillis() + ": adding task");
131: timer.add(new OneTimeTask(500));
132: size = timer.size();
133: System.out.println("queue size=" + size);
134: assertEquals(1, size);
135: Util.sleep(1000);
136: size = timer.size();
137: System.out.println("queue size=" + size);
138: assertEquals(0, size);
139:
140: Util.sleep(1500);
141: System.out
142: .println(System.currentTimeMillis() + ": adding task");
143: timer.add(new OneTimeTask(500));
144:
145: System.out
146: .println(System.currentTimeMillis() + ": adding task");
147: timer.add(new OneTimeTask(500));
148:
149: System.out
150: .println(System.currentTimeMillis() + ": adding task");
151: timer.add(new OneTimeTask(500));
152:
153: size = timer.size();
154: System.out.println("queue size=" + size);
155: assertEquals(3, size);
156:
157: Util.sleep(1000);
158: size = timer.size();
159: System.out.println("queue size=" + size);
160: assertEquals(0, size);
161: }
162:
163: public void testRepeatingTask() {
164: System.out
165: .println(System.currentTimeMillis() + ": adding task");
166: RepeatingTask task = new RepeatingTask(500);
167: timer.add(task);
168: Util.sleep(5000);
169:
170: System.out.println("<<< cancelling task");
171: task.done();
172: Util.sleep(2000);
173: int num = task.getNum();
174: System.out.println("task executed " + num + " times");
175: assertTrue(num >= 9 && num < 11);
176: }
177:
178: /**
179: * Tests whether retransmits are called at correct times for 1000 messages. A retransmit should not be
180: * more than 30% earlier or later than the scheduled retransmission time
181: */
182: public void testRetransmits() {
183: Entry entry;
184: int num_non_correct_entries = 0;
185:
186: // 1. Add NUM_MSGS messages:
187: System.out.println("-- adding " + NUM_MSGS + " messages:");
188: for (long i = 0; i < NUM_MSGS; i++) {
189: entry = new Entry(i);
190: msgs.put(new Long(i), entry);
191: timer.add(entry);
192: }
193: System.out.println("-- done");
194:
195: // 2. Wait for at least 4 xmits/msg: total of 1000 + 2000 + 4000 + 8000ms = 15000ms; wait for 20000ms
196: System.out
197: .println("-- waiting for 20 secs for all retransmits");
198: Util.sleep(20000);
199:
200: // 3. Check whether all Entries have correct retransmission times
201: for (long i = 0; i < NUM_MSGS; i++) {
202: entry = (Entry) msgs.get(new Long(i));
203: if (!entry.isCorrect()) {
204: num_non_correct_entries++;
205: }
206: }
207:
208: if (num_non_correct_entries > 0)
209: System.err
210: .println("Number of incorrect retransmission timeouts: "
211: + num_non_correct_entries);
212: else {
213: for (long i = 0; i < NUM_MSGS; i++) {
214: entry = (Entry) msgs.get(new Long(i));
215: if (entry != null)
216: System.out.println(i + ": " + entry);
217: }
218: }
219: assertEquals(0, num_non_correct_entries);
220: }
221:
222: static private class ImmediateTask implements TimeScheduler.Task {
223: Promise p;
224: boolean executed = false;
225:
226: public ImmediateTask(Promise p) {
227: this .p = p;
228: }
229:
230: public boolean cancelled() {
231: return executed;
232: }
233:
234: public long nextInterval() {
235: return 0;
236: }
237:
238: public void run() {
239: p.setResult(Boolean.TRUE);
240: executed = true;
241: }
242: }
243:
244: static class OneTimeTask implements TimeScheduler.Task {
245: boolean done = false;
246: private long timeout = 0;
247:
248: OneTimeTask(long timeout) {
249: this .timeout = timeout;
250: }
251:
252: public boolean cancelled() {
253: return done;
254: }
255:
256: public void done() {
257: done = true;
258: }
259:
260: public long nextInterval() {
261: return timeout;
262: }
263:
264: public void run() {
265: System.out.println(System.currentTimeMillis()
266: + ": this is MyTask running - done");
267: done = true;
268: }
269: }
270:
271: static class RepeatingTask extends OneTimeTask {
272: int num = 0;
273:
274: RepeatingTask(long timeout) {
275: super (timeout);
276: }
277:
278: public int getNum() {
279: return num;
280: }
281:
282: public void run() {
283: System.out.println((num + 1)
284: + ": this is the repeating task");
285: num++;
286: }
287: }
288:
289: static class StressTask implements TimeScheduler.Task {
290: boolean cancelled = false;
291: int num_executions = 0;
292:
293: public void cancel() {
294: cancelled = true;
295: }
296:
297: public boolean cancelled() {
298: return cancelled;
299: }
300:
301: public long nextInterval() {
302: return 50;
303: }
304:
305: public void run() {
306: // System.out.println("executed");
307: num_executions++;
308: }
309:
310: public int getNum_executions() {
311: return num_executions;
312: }
313: }
314:
315: class Entry implements TimeScheduler.Task {
316: long start_time = 0; // time message was added
317: long first_xmit = 0; // time between start_time and first_xmit should be ca. 1000ms
318: long second_xmit = 0; // time between first_xmit and second_xmit should be ca. 2000ms
319: long third_xmit = 0; // time between third_xmit and second_xmit should be ca. 4000ms
320: long fourth_xmit = 0; // time between third_xmit and second_xmit should be ca. 8000ms
321: boolean cancelled = false;
322: Interval interval = new Interval(xmit_timeouts);
323: long seqno = 0;
324:
325: Entry(long seqno) {
326: this .seqno = seqno;
327: start_time = System.currentTimeMillis();
328: }
329:
330: public void cancel() {
331: cancelled = true;
332: }
333:
334: public boolean cancelled() {
335: return cancelled;
336: }
337:
338: public long nextInterval() {
339: return interval.next();
340: }
341:
342: public void run() {
343: if (first_xmit == 0)
344: first_xmit = System.currentTimeMillis();
345: else if (second_xmit == 0)
346: second_xmit = System.currentTimeMillis();
347: else if (third_xmit == 0)
348: third_xmit = System.currentTimeMillis();
349: else if (fourth_xmit == 0)
350: fourth_xmit = System.currentTimeMillis();
351: }
352:
353: /**
354: * Entry is correct if xmit timeouts are not more than 30% off the mark
355: */
356: boolean isCorrect() {
357: long t;
358: long expected;
359: long diff, delta;
360: boolean off = false;
361:
362: t = first_xmit - start_time;
363: expected = xmit_timeouts[0];
364: diff = Math.abs(expected - t);
365: delta = (long) (expected * PERCENTAGE_OFF);
366: if (diff >= delta)
367: off = true;
368:
369: t = second_xmit - first_xmit;
370: expected = xmit_timeouts[1];
371: diff = Math.abs(expected - t);
372: delta = (long) (expected * PERCENTAGE_OFF);
373: if (diff >= delta)
374: off = true;
375:
376: t = third_xmit - second_xmit;
377: expected = xmit_timeouts[2];
378: diff = Math.abs(expected - t);
379: delta = (long) (expected * PERCENTAGE_OFF);
380: if (diff >= delta)
381: off = true;
382:
383: t = fourth_xmit - third_xmit;
384: expected = xmit_timeouts[3];
385: diff = Math.abs(expected - t);
386: delta = (long) (expected * PERCENTAGE_OFF);
387: if (diff >= delta)
388: off = true;
389:
390: if (off) {
391: System.err.println("#" + seqno + ": " + this + ": ("
392: + "entry is more than " + PERCENTAGE_OFF
393: + " percentage off ");
394: return false;
395: }
396: return true;
397: }
398:
399: public String toString() {
400: StringBuffer sb = new StringBuffer();
401: sb.append(first_xmit - start_time).append(", ").append(
402: second_xmit - first_xmit).append(", ");
403: sb.append(third_xmit - second_xmit).append(", ").append(
404: fourth_xmit - third_xmit);
405: return sb.toString();
406: }
407: }
408:
409: public static Test suite() {
410: TestSuite suite;
411: suite = new TestSuite(TimeSchedulerTest.class);
412: return (suite);
413: }
414:
415: public static void main(String[] args) {
416: String[] name = { TimeSchedulerTest.class.getName() };
417: junit.textui.TestRunner.main(name);
418: }
419: }
|