KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > foxtrot > test > WorkerTest


1 /**
2  * Copyright (c) 2002-2005, Simone Bordet
3  * All rights reserved.
4  *
5  * This software is distributable under the BSD license.
6  * See the terms of the BSD license in the documentation provided with this software.
7  */

8
9 package foxtrot.test;
10
11 import java.awt.event.ActionEvent JavaDoc;
12 import java.awt.event.ActionListener JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15
16 import javax.swing.JButton JavaDoc;
17 import javax.swing.JDialog JavaDoc;
18 import javax.swing.JFrame JavaDoc;
19 import javax.swing.SwingUtilities JavaDoc;
20
21 import foxtrot.Job;
22 import foxtrot.Task;
23 import foxtrot.Worker;
24
25 /**
26  * @version $Revision: 1.4 $
27  */

28 public class WorkerTest extends FoxtrotTestCase
29 {
30    public WorkerTest(String JavaDoc s)
31    {
32       super(s);
33    }
34
35    public void testThreads() throws Exception JavaDoc
36    {
37       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
38       {
39          public void run()
40          {
41             Worker.post(new Job()
42             {
43                public Object JavaDoc run()
44                {
45                   // Check that I'm NOT in the AWT Event Dispatch Thread
46
if (SwingUtilities.isEventDispatchThread()) fail("Must not be in the Event Dispatch Thread");
47
48                   // Check that I'm really in the Foxtrot Worker Thread
49
if (Thread.currentThread().getName().indexOf("Foxtrot") < 0) fail("Must be in the Foxtrot Worker Thread");
50
51                   return null;
52                }
53             });
54          }
55       }, null);
56    }
57
58    public void testBlocking() throws Exception JavaDoc
59    {
60       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
61       {
62          public void run()
63          {
64             final long sleep = 1000;
65
66             long start = System.currentTimeMillis();
67             Worker.post(new Job()
68             {
69                public Object JavaDoc run()
70                {
71                   sleep(sleep);
72                   return null;
73                }
74             });
75             long end = System.currentTimeMillis();
76
77             long elapsed = end - start;
78             System.out.println("Sleep time is: " + sleep + ", Worker.post() blocked for " + elapsed);
79
80             if (elapsed < sleep) fail("Worker.post() does not block");
81          }
82       }, null);
83    }
84
85    public void testDequeuing() throws Exception JavaDoc
86    {
87       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
88       {
89          public void run()
90          {
91             final MutableInteger check = new MutableInteger(0);
92             final long sleep = 1000;
93
94             // This event will be dequeued only after Worker.post()
95
SwingUtilities.invokeLater(new Runnable JavaDoc()
96             {
97                public void run()
98                {
99                   check.set(1);
100                }
101             });
102
103             sleep(2 * sleep);
104
105             // Check that the value is still the original one
106
if (check.get() != 0) fail();
107
108             Worker.post(new Job()
109             {
110                public Object JavaDoc run()
111                {
112                   sleep(sleep);
113                   return null;
114                }
115             });
116
117             // Check that the event posted with invokeLater has been dequeued
118
if (check.get() != 1) fail("Event has not been dequeued");
119          }
120       }, null);
121    }
122
123    public void testTaskException() throws Exception JavaDoc
124    {
125       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
126       {
127          public void run()
128          {
129             try
130             {
131                Worker.post(new Task()
132                {
133                   public Object JavaDoc run() throws NumberFormatException JavaDoc
134                   {
135                      return new NumberFormatException JavaDoc();
136                   }
137                });
138             }
139             catch (NumberFormatException JavaDoc ignored)
140             {
141             }
142             catch (Throwable JavaDoc x)
143             {
144                fail();
145             }
146          }
147       }, null);
148    }
149
150    public void testTaskError() throws Exception JavaDoc
151    {
152       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
153       {
154          public void run()
155          {
156             try
157             {
158                Worker.post(new Job()
159                {
160                   public Object JavaDoc run()
161                   {
162                      return new NoClassDefFoundError JavaDoc();
163                   }
164                });
165             }
166             catch (NoClassDefFoundError JavaDoc ignored)
167             {
168             }
169             catch (Throwable JavaDoc x)
170             {
171                fail();
172             }
173          }
174       }, null);
175    }
176
177    public void testAWTException() throws Exception JavaDoc
178    {
179       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
180       {
181          public void run()
182          {
183             SwingUtilities.invokeLater(new Runnable JavaDoc()
184             {
185                public void run()
186                {
187                   throw new RuntimeException JavaDoc();
188                }
189             });
190
191             final long sleep = 1000;
192             long start = System.currentTimeMillis();
193             Worker.post(new Job()
194             {
195                public Object JavaDoc run()
196                {
197                   sleep(sleep);
198                   return null;
199                }
200             });
201             long end = System.currentTimeMillis();
202
203             // Must check that really elapsed all the time
204
long elapsed = end - start;
205             if (elapsed < sleep) fail("Worker.post() does not block in case of AWT exception: expected " + sleep + ", waited " + elapsed);
206          }
207       }, null);
208    }
209
210    public void testAWTError() throws Exception JavaDoc
211    {
212       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
213       {
214          public void run()
215          {
216             SwingUtilities.invokeLater(new Runnable JavaDoc()
217             {
218                public void run()
219                {
220                   throw new Error JavaDoc();
221                }
222             });
223
224             final long sleep = 1000;
225             long start = System.currentTimeMillis();
226             Worker.post(new Job()
227             {
228                public Object JavaDoc run()
229                {
230                   sleep(sleep);
231                   return null;
232                }
233             });
234             long end = System.currentTimeMillis();
235
236             // Must check that really elapsed all the time
237
long elapsed = end - start;
238             if (elapsed < sleep) fail("Worker.post() does not block in case of AWT error: expected " + sleep + ", waited " + elapsed);
239          }
240       }, null);
241    }
242
243    public void testPostFromTask() throws Exception JavaDoc
244    {
245       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
246       {
247          public void run()
248          {
249             final MutableInteger counter = new MutableInteger(0);
250
251             Worker.post(new Job()
252             {
253                public Object JavaDoc run()
254                {
255                   counter.set(counter.get() + 1);
256
257                   // Nested Worker.post()
258
Worker.post(new Job()
259                   {
260                      public Object JavaDoc run()
261                      {
262                         if (counter.get() != 1) fail();
263
264                         counter.set(counter.get() + 1);
265                         return null;
266                      }
267                   });
268
269                   if (counter.get() != 2) fail("Nested Task is not executed immediately");
270
271                   counter.set(counter.get() + 1);
272
273                   return null;
274                }
275             });
276
277             if (counter.get() != 3) fail();
278          }
279       }, null);
280    }
281
282    public void testTaskReuse() throws Exception JavaDoc
283    {
284       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
285       {
286          public void run()
287          {
288             final MutableInteger count = new MutableInteger(0);
289
290             Job job = new Job()
291             {
292                public Object JavaDoc run()
293                {
294                   count.set(count.get() + 1);
295                   return null;
296                }
297             };
298
299             int times = 2;
300             for (int i = 0; i < times; ++i)
301             {
302                Worker.post(job);
303             }
304
305             if (count.get() != times) fail("Task is not reused");
306          }
307       }, null);
308    }
309
310    public void testPostFromInvokeLater() throws Exception JavaDoc
311    {
312       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
313       {
314          public void run()
315          {
316             int max = 5;
317             MutableInteger counter = new MutableInteger(0);
318
319             long start = System.currentTimeMillis();
320
321             postFromInvokeLater(counter, max);
322
323             long end = System.currentTimeMillis();
324
325             // We used the default WorkerThread, be sure task times were summed
326
long sum = 0;
327             for (int i = 0; i < max; ++i) sum += i + 1;
328             sum *= 1000;
329
330             long epsilon = 100;
331             long elapsed = end - start;
332             if (elapsed > sum + epsilon) fail("Elapsed time is: " + elapsed + ", expected time is: " + sum);
333             if (elapsed < sum - epsilon) fail("Elapsed time is: " + elapsed + ", expected time is: " + sum);
334          }
335       }, null);
336    }
337
338    private void postFromInvokeLater(final MutableInteger counter, final int maxDeep)
339    {
340       final int deep = counter.get() + 1;
341
342       Job job = new Job()
343       {
344          public Object JavaDoc run()
345          {
346             // Here I recurse on calling Worker.post(), that is: I am in event0, that calls
347
// Worker.post(task1) that dequeues event1 that calls Worker.post(task2) that dequeues event2
348
// that calls Worker.post(task3) and so on.
349
// Since Worker.post() calls are synchronous, the Worker.post(task1) call returns
350
// only when the task1 is finished AND event1 is finished; but event1 is finished
351
// only when Worker.post(task2) returns; Worker.post(task2) returns only when task2
352
// is finished AND event2 is finished; but event2 is finished only when Worker.post(task3)
353
// returns; and so on.
354
// The total execution time is dependent on the implementation of the WorkerThread:
355
// if it enqueues tasks (like the default implementation) we have (roughly) that:
356
// time(task1) = time(task3) + time(task2)
357
// even if to execute only task1 taskes a very short time.
358
// If the worker implementation uses parallel threads to execute tasks, then (roughly):
359
// time(task1) = max(time(task3), time(task2)).
360
// In general, it is a bad idea to use Foxtrot this way: you probably need an asynchronous
361
// solution.
362
SwingUtilities.invokeLater(new Runnable JavaDoc()
363             {
364                public void run()
365                {
366                   counter.set(deep);
367                   if (deep < maxDeep) postFromInvokeLater(counter, maxDeep);
368                }
369             });
370
371             sleep(1000 * deep);
372
373             return null;
374          }
375       };
376
377       // job1 sleeps 1 s, but Worker.post(job1) returns after event1 is finished.
378
// event1 runs Worker.post(job2); job2 sleeps 2 s, but Worker.post(job2) returns after event2 is finished.
379
// event2 runs Worker.post(job3); job3 sleeps 3 s, but Worker.post(job3) returns after event3 is finished.
380
// event3 runs Worker.post(job4); job4 sleeps 4 s, but Worker.post(job4) returns after event4 is finished.
381
// event4 runs Worker.post(job5); job5 sleeps 5 s.
382
// Worker.post(job1) returns after 5+4+3+2+1 s since the default implementation enqueues tasks.
383
Worker.post(job);
384    }
385
386    public void testTaskQueueing() throws Exception JavaDoc
387    {
388       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
389       {
390          public void run()
391          {
392             final int count = 10;
393             final MutableInteger counter = new MutableInteger(0);
394
395             // From Worker.post() I post some event on the Event Queue using invokeLater.
396
// The events posted are dequeued and they call again Worker.post(),
397
// that is not yet returned, so that Tasks are queued in the worker thread,
398
// and not yet executed. When the first Worker.post() returns, the enqueued
399
// Tasks get a chance to be executed.
400
Worker.post(new Job()
401             {
402                public Object JavaDoc run()
403                {
404                   for (int i = 0; i < 10; ++i)
405                   {
406                      SwingUtilities.invokeLater(new Runnable JavaDoc()
407                      {
408                         public void run()
409                         {
410                            Worker.post(new Job()
411                            {
412                               public Object JavaDoc run()
413                               {
414                                  counter.set(counter.get() + 1);
415                                  return null;
416                               }
417                            });
418                         }
419                      });
420                   }
421
422                   // Wait for all tasks to be queued in the worker thread.
423
sleep(1000);
424
425                   return null;
426                }
427             });
428
429             // Wait for all the enqueued Tasks in the worker thread to be executed.
430
sleep(1000);
431
432             assertEquals(count, counter.get());
433          }
434       }, null);
435    }
436
437    public void testPerformance() throws Exception JavaDoc
438    {
439       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
440       {
441          public void run()
442          {
443             JButton JavaDoc button = new JButton JavaDoc();
444             int count = 100;
445             final long sleep = 100;
446
447             ActionListener JavaDoc listener = new ActionListener JavaDoc()
448             {
449                public void actionPerformed(ActionEvent JavaDoc e)
450                {
451                   Worker.post(new Job()
452                   {
453                      public Object JavaDoc run()
454                      {
455                         sleep(sleep);
456                         return null;
457                      }
458                   });
459                }
460             };
461             button.addActionListener(listener);
462
463             long start = System.currentTimeMillis();
464             for (int i = 0; i < count; ++i) button.doClick();
465             long end = System.currentTimeMillis();
466             long workerElapsed = end - start;
467             System.out.println("Worker.post(Job) performance: " + count + " calls in " + workerElapsed + " ms");
468
469             button.removeActionListener(listener);
470
471             listener = new ActionListener JavaDoc()
472             {
473                public void actionPerformed(ActionEvent JavaDoc e)
474                {
475                   sleep(sleep);
476                }
477             };
478             button.addActionListener(listener);
479
480             start = System.currentTimeMillis();
481             for (int i = 0; i < count; ++i)
482             {
483                button.doClick();
484             }
485             end = System.currentTimeMillis();
486             long plainElapsed = end - start;
487             System.out.println("Plain Listener performance: " + count + " calls in " + plainElapsed + " ms");
488
489             int perthousand = 1;
490             if ((workerElapsed - plainElapsed) * 1000 > plainElapsed * perthousand) fail();
491          }
492       }, null);
493    }
494
495    public void testPumpSequencedEvents() throws Exception JavaDoc
496    {
497       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
498       {
499          public void run()
500          {
501             final JDialog JavaDoc dialog = new JDialog JavaDoc((JFrame JavaDoc)null, true);
502
503             SwingUtilities.invokeLater(new Runnable JavaDoc()
504             {
505                public void run()
506                {
507                   dialog.setVisible(false);
508                }
509             });
510
511             dialog.setVisible(true);
512
513             final MutableInteger pumped = new MutableInteger(0);
514             SwingUtilities.invokeLater(new Runnable JavaDoc()
515             {
516                public void run()
517                {
518                   pumped.set(pumped.get() + 1);
519                }
520             });
521
522             Worker.post(new Job()
523             {
524                public Object JavaDoc run()
525                {
526                   sleep(1000);
527                   return null;
528                }
529             });
530
531             // Verify that the event has been pumped
532
if (pumped.get() != 1) fail();
533          }
534       }, null);
535    }
536
537    public void testMemoryLeaks() throws Exception JavaDoc
538    {
539       invokeTest(Worker.getWorkerThread(), new Runnable JavaDoc()
540       {
541          public void run()
542          {
543             ArrayList JavaDoc list = new ArrayList JavaDoc();
544
545             int times = 1024;
546             for (int i = 0; i < times; ++i)
547             {
548                try
549                {
550                   Job job = new FatJob();
551                   list.add(job);
552                   Worker.post(job);
553                }
554                catch (OutOfMemoryError JavaDoc x)
555                {
556                   list.clear();
557                   break;
558                }
559             }
560
561             // Try again, without mantaining jobs alive
562
int j = 0;
563             for (; j < times; ++j)
564             {
565                Job job = new FatJob();
566                Worker.post(job);
567             }
568
569             if (j < times) fail();
570          }
571       }, null);
572    }
573
574    private static class FatJob extends Job
575    {
576       // A heavy data member to explode the heap
577
private byte[] fatty = new byte[1024 * 1024];
578
579       public Object JavaDoc run()
580       {
581          Arrays.fill(fatty, (byte)31);
582          return null;
583       }
584    }
585 }
586
Popular Tags