1 /*
2  * Written by Doug Lea with assistance from members of JCP JSR-166
3  * Expert Group and released to the public domain, as explained at
4  * http://creativecommons.org/publicdomain/zero/1.0/
5  * Other contributors include Andrew Wright, Jeffrey Hayes,
6  * Pat Fisher, Mike Judd.
7  */
8 
9 package jsr166;
10 
11 import static java.util.concurrent.TimeUnit.MILLISECONDS;
12 
13 import java.security.PrivilegedAction;
14 import java.security.PrivilegedExceptionAction;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.concurrent.AbstractExecutorService;
19 import java.util.concurrent.ArrayBlockingQueue;
20 import java.util.concurrent.Callable;
21 import java.util.concurrent.CancellationException;
22 import java.util.concurrent.CountDownLatch;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Executors;
25 import java.util.concurrent.ExecutorService;
26 import java.util.concurrent.Future;
27 import java.util.concurrent.ThreadPoolExecutor;
28 import java.util.concurrent.TimeUnit;
29 import java.util.concurrent.atomic.AtomicBoolean;
30 
31 import junit.framework.Test;
32 import junit.framework.TestSuite;
33 
34 public class AbstractExecutorServiceTest extends JSR166TestCase {
35     // android-note: Removed because the CTS runner does a bad job of
36     // retrying tests that have suite() declarations.
37     //
38     // public static void main(String[] args) {
39     //     main(suite(), args);
40     // }
41     // public static Test suite() {
42     //     return new TestSuite(AbstractExecutorServiceTest.class);
43     // }
44 
45     /**
46      * A no-frills implementation of AbstractExecutorService, designed
47      * to test the submit methods only.
48      */
49     static class DirectExecutorService extends AbstractExecutorService {
execute(Runnable r)50         public void execute(Runnable r) { r.run(); }
shutdown()51         public void shutdown() { shutdown = true; }
shutdownNow()52         public List<Runnable> shutdownNow() {
53             shutdown = true;
54             return Collections.EMPTY_LIST;
55         }
isShutdown()56         public boolean isShutdown() { return shutdown; }
isTerminated()57         public boolean isTerminated() { return isShutdown(); }
awaitTermination(long timeout, TimeUnit unit)58         public boolean awaitTermination(long timeout, TimeUnit unit) {
59             return isShutdown();
60         }
61         private volatile boolean shutdown = false;
62     }
63 
64     /**
65      * execute(runnable) runs it to completion
66      */
testExecuteRunnable()67     public void testExecuteRunnable() throws Exception {
68         ExecutorService e = new DirectExecutorService();
69         final AtomicBoolean done = new AtomicBoolean(false);
70         Future<?> future = e.submit(new CheckedRunnable() {
71             public void realRun() {
72                 done.set(true);
73             }});
74         assertNull(future.get());
75         assertNull(future.get(0, MILLISECONDS));
76         assertTrue(done.get());
77         assertTrue(future.isDone());
78         assertFalse(future.isCancelled());
79     }
80 
81     /**
82      * Completed submit(callable) returns result
83      */
testSubmitCallable()84     public void testSubmitCallable() throws Exception {
85         ExecutorService e = new DirectExecutorService();
86         Future<String> future = e.submit(new StringTask());
87         String result = future.get();
88         assertSame(TEST_STRING, result);
89     }
90 
91     /**
92      * Completed submit(runnable) returns successfully
93      */
testSubmitRunnable()94     public void testSubmitRunnable() throws Exception {
95         ExecutorService e = new DirectExecutorService();
96         Future<?> future = e.submit(new NoOpRunnable());
97         future.get();
98         assertTrue(future.isDone());
99     }
100 
101     /**
102      * Completed submit(runnable, result) returns result
103      */
testSubmitRunnable2()104     public void testSubmitRunnable2() throws Exception {
105         ExecutorService e = new DirectExecutorService();
106         Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
107         String result = future.get();
108         assertSame(TEST_STRING, result);
109     }
110 
111     /**
112      * A submitted privileged action runs to completion
113      */
testSubmitPrivilegedAction()114     public void testSubmitPrivilegedAction() throws Exception {
115         Runnable r = new CheckedRunnable() {
116             public void realRun() throws Exception {
117                 ExecutorService e = new DirectExecutorService();
118                 Future future = e.submit(Executors.callable(new PrivilegedAction() {
119                     public Object run() {
120                         return TEST_STRING;
121                     }}));
122 
123                 assertSame(TEST_STRING, future.get());
124             }};
125 
126         runWithPermissions(r,
127                            new RuntimePermission("getClassLoader"),
128                            new RuntimePermission("setContextClassLoader"),
129                            new RuntimePermission("modifyThread"));
130     }
131 
132     /**
133      * A submitted privileged exception action runs to completion
134      */
testSubmitPrivilegedExceptionAction()135     public void testSubmitPrivilegedExceptionAction() throws Exception {
136         Runnable r = new CheckedRunnable() {
137             public void realRun() throws Exception {
138                 ExecutorService e = new DirectExecutorService();
139                 Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() {
140                     public Object run() {
141                         return TEST_STRING;
142                     }}));
143 
144                 assertSame(TEST_STRING, future.get());
145             }};
146 
147         runWithPermissions(r);
148     }
149 
150     /**
151      * A submitted failed privileged exception action reports exception
152      */
testSubmitFailedPrivilegedExceptionAction()153     public void testSubmitFailedPrivilegedExceptionAction() throws Exception {
154         Runnable r = new CheckedRunnable() {
155             public void realRun() throws Exception {
156                 ExecutorService e = new DirectExecutorService();
157                 Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() {
158                     public Object run() throws Exception {
159                         throw new IndexOutOfBoundsException();
160                     }}));
161 
162                 try {
163                     future.get();
164                     shouldThrow();
165                 } catch (ExecutionException success) {
166                     assertTrue(success.getCause() instanceof IndexOutOfBoundsException);
167                 }}};
168 
169         runWithPermissions(r);
170     }
171 
172     /**
173      * execute(null runnable) throws NPE
174      */
testExecuteNullRunnable()175     public void testExecuteNullRunnable() {
176         ExecutorService e = new DirectExecutorService();
177         try {
178             e.submit((Runnable) null);
179             shouldThrow();
180         } catch (NullPointerException success) {}
181     }
182 
183     /**
184      * submit(null callable) throws NPE
185      */
testSubmitNullCallable()186     public void testSubmitNullCallable() {
187         ExecutorService e = new DirectExecutorService();
188         try {
189             e.submit((Callable) null);
190             shouldThrow();
191         } catch (NullPointerException success) {}
192     }
193 
194     /**
195      * submit(callable).get() throws InterruptedException if interrupted
196      */
testInterruptedSubmit()197     public void testInterruptedSubmit() throws InterruptedException {
198         final CountDownLatch submitted    = new CountDownLatch(1);
199         final CountDownLatch quittingTime = new CountDownLatch(1);
200         final Callable<Void> awaiter = new CheckedCallable<Void>() {
201             public Void realCall() throws InterruptedException {
202                 assertTrue(quittingTime.await(2*LONG_DELAY_MS, MILLISECONDS));
203                 return null;
204             }};
205         final ExecutorService p
206             = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS,
207                                      new ArrayBlockingQueue<Runnable>(10));
208         try (PoolCleaner cleaner = cleaner(p, quittingTime)) {
209             Thread t = newStartedThread(new CheckedInterruptedRunnable() {
210                 public void realRun() throws Exception {
211                     Future<Void> future = p.submit(awaiter);
212                     submitted.countDown();
213                     future.get();
214                 }});
215 
216             await(submitted);
217             t.interrupt();
218             awaitTermination(t);
219         }
220     }
221 
222     /**
223      * get of submit(callable) throws ExecutionException if callable
224      * throws exception
225      */
testSubmitEE()226     public void testSubmitEE() throws InterruptedException {
227         final ThreadPoolExecutor p =
228             new ThreadPoolExecutor(1, 1,
229                                    60, TimeUnit.SECONDS,
230                                    new ArrayBlockingQueue<Runnable>(10));
231         try (PoolCleaner cleaner = cleaner(p)) {
232             Callable c = new Callable() {
233                 public Object call() { throw new ArithmeticException(); }};
234             try {
235                 p.submit(c).get();
236                 shouldThrow();
237             } catch (ExecutionException success) {
238                 assertTrue(success.getCause() instanceof ArithmeticException);
239             }
240         }
241     }
242 
243     /**
244      * invokeAny(null) throws NPE
245      */
testInvokeAny1()246     public void testInvokeAny1() throws Exception {
247         final ExecutorService e = new DirectExecutorService();
248         try (PoolCleaner cleaner = cleaner(e)) {
249             try {
250                 e.invokeAny(null);
251                 shouldThrow();
252             } catch (NullPointerException success) {}
253         }
254     }
255 
256     /**
257      * invokeAny(empty collection) throws IAE
258      */
testInvokeAny2()259     public void testInvokeAny2() throws Exception {
260         final ExecutorService e = new DirectExecutorService();
261         try (PoolCleaner cleaner = cleaner(e)) {
262             try {
263                 e.invokeAny(new ArrayList<Callable<String>>());
264                 shouldThrow();
265             } catch (IllegalArgumentException success) {}
266         }
267     }
268 
269     /**
270      * invokeAny(c) throws NPE if c has null elements
271      */
testInvokeAny3()272     public void testInvokeAny3() throws Exception {
273         final ExecutorService e = new DirectExecutorService();
274         try (PoolCleaner cleaner = cleaner(e)) {
275             List<Callable<Long>> l = new ArrayList<Callable<Long>>();
276             l.add(new Callable<Long>() {
277                       public Long call() { throw new ArithmeticException(); }});
278             l.add(null);
279             try {
280                 e.invokeAny(l);
281                 shouldThrow();
282             } catch (NullPointerException success) {}
283         }
284     }
285 
286     /**
287      * invokeAny(c) throws ExecutionException if no task in c completes
288      */
testInvokeAny4()289     public void testInvokeAny4() throws InterruptedException {
290         final ExecutorService e = new DirectExecutorService();
291         try (PoolCleaner cleaner = cleaner(e)) {
292             List<Callable<String>> l = new ArrayList<Callable<String>>();
293             l.add(new NPETask());
294             try {
295                 e.invokeAny(l);
296                 shouldThrow();
297             } catch (ExecutionException success) {
298                 assertTrue(success.getCause() instanceof NullPointerException);
299             }
300         }
301     }
302 
303     /**
304      * invokeAny(c) returns result of some task in c if at least one completes
305      */
testInvokeAny5()306     public void testInvokeAny5() throws Exception {
307         final ExecutorService e = new DirectExecutorService();
308         try (PoolCleaner cleaner = cleaner(e)) {
309             List<Callable<String>> l = new ArrayList<Callable<String>>();
310             l.add(new StringTask());
311             l.add(new StringTask());
312             String result = e.invokeAny(l);
313             assertSame(TEST_STRING, result);
314         }
315     }
316 
317     /**
318      * invokeAll(null) throws NPE
319      */
testInvokeAll1()320     public void testInvokeAll1() throws InterruptedException {
321         final ExecutorService e = new DirectExecutorService();
322         try (PoolCleaner cleaner = cleaner(e)) {
323             try {
324                 e.invokeAll(null);
325                 shouldThrow();
326             } catch (NullPointerException success) {}
327         }
328     }
329 
330     /**
331      * invokeAll(empty collection) returns empty collection
332      */
testInvokeAll2()333     public void testInvokeAll2() throws InterruptedException {
334         final ExecutorService e = new DirectExecutorService();
335         try (PoolCleaner cleaner = cleaner(e)) {
336             List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
337             assertTrue(r.isEmpty());
338         }
339     }
340 
341     /**
342      * invokeAll(c) throws NPE if c has null elements
343      */
testInvokeAll3()344     public void testInvokeAll3() throws InterruptedException {
345         final ExecutorService e = new DirectExecutorService();
346         try (PoolCleaner cleaner = cleaner(e)) {
347             List<Callable<String>> l = new ArrayList<Callable<String>>();
348             l.add(new StringTask());
349             l.add(null);
350             try {
351                 e.invokeAll(l);
352                 shouldThrow();
353             } catch (NullPointerException success) {}
354         }
355     }
356 
357     /**
358      * get of returned element of invokeAll(c) throws exception on failed task
359      */
testInvokeAll4()360     public void testInvokeAll4() throws Exception {
361         final ExecutorService e = new DirectExecutorService();
362         try (PoolCleaner cleaner = cleaner(e)) {
363             List<Callable<String>> l = new ArrayList<Callable<String>>();
364             l.add(new NPETask());
365             List<Future<String>> futures = e.invokeAll(l);
366             assertEquals(1, futures.size());
367             try {
368                 futures.get(0).get();
369                 shouldThrow();
370             } catch (ExecutionException success) {
371                 assertTrue(success.getCause() instanceof NullPointerException);
372             }
373         }
374     }
375 
376     /**
377      * invokeAll(c) returns results of all completed tasks in c
378      */
testInvokeAll5()379     public void testInvokeAll5() throws Exception {
380         final ExecutorService e = new DirectExecutorService();
381         try (PoolCleaner cleaner = cleaner(e)) {
382             List<Callable<String>> l = new ArrayList<Callable<String>>();
383             l.add(new StringTask());
384             l.add(new StringTask());
385             List<Future<String>> futures = e.invokeAll(l);
386             assertEquals(2, futures.size());
387             for (Future<String> future : futures)
388                 assertSame(TEST_STRING, future.get());
389         }
390     }
391 
392     /**
393      * timed invokeAny(null) throws NPE
394      */
testTimedInvokeAny1()395     public void testTimedInvokeAny1() throws Exception {
396         final ExecutorService e = new DirectExecutorService();
397         try (PoolCleaner cleaner = cleaner(e)) {
398             try {
399                 e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
400                 shouldThrow();
401             } catch (NullPointerException success) {}
402         }
403     }
404 
405     /**
406      * timed invokeAny(null time unit) throws NPE
407      */
testTimedInvokeAnyNullTimeUnit()408     public void testTimedInvokeAnyNullTimeUnit() throws Exception {
409         final ExecutorService e = new DirectExecutorService();
410         try (PoolCleaner cleaner = cleaner(e)) {
411             List<Callable<String>> l = new ArrayList<Callable<String>>();
412             l.add(new StringTask());
413             try {
414                 e.invokeAny(l, MEDIUM_DELAY_MS, null);
415                 shouldThrow();
416             } catch (NullPointerException success) {}
417         }
418     }
419 
420     /**
421      * timed invokeAny(empty collection) throws IAE
422      */
testTimedInvokeAny2()423     public void testTimedInvokeAny2() throws Exception {
424         final ExecutorService e = new DirectExecutorService();
425         try (PoolCleaner cleaner = cleaner(e)) {
426             try {
427                 e.invokeAny(new ArrayList<Callable<String>>(),
428                             MEDIUM_DELAY_MS, MILLISECONDS);
429                 shouldThrow();
430             } catch (IllegalArgumentException success) {}
431         }
432     }
433 
434     /**
435      * timed invokeAny(c) throws NPE if c has null elements
436      */
testTimedInvokeAny3()437     public void testTimedInvokeAny3() throws Exception {
438         final ExecutorService e = new DirectExecutorService();
439         try (PoolCleaner cleaner = cleaner(e)) {
440             List<Callable<Long>> l = new ArrayList<Callable<Long>>();
441             l.add(new Callable<Long>() {
442                       public Long call() { throw new ArithmeticException(); }});
443             l.add(null);
444             try {
445                 e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
446                 shouldThrow();
447             } catch (NullPointerException success) {}
448         }
449     }
450 
451     /**
452      * timed invokeAny(c) throws ExecutionException if no task completes
453      */
testTimedInvokeAny4()454     public void testTimedInvokeAny4() throws Exception {
455         final ExecutorService e = new DirectExecutorService();
456         try (PoolCleaner cleaner = cleaner(e)) {
457             long startTime = System.nanoTime();
458             List<Callable<String>> l = new ArrayList<Callable<String>>();
459             l.add(new NPETask());
460             try {
461                 e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
462                 shouldThrow();
463             } catch (ExecutionException success) {
464                 assertTrue(success.getCause() instanceof NullPointerException);
465             }
466             assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
467         }
468     }
469 
470     /**
471      * timed invokeAny(c) returns result of some task in c
472      */
473     public void testTimedInvokeAny5() throws Exception {
474         final ExecutorService e = new DirectExecutorService();
475         try (PoolCleaner cleaner = cleaner(e)) {
476             long startTime = System.nanoTime();
477             List<Callable<String>> l = new ArrayList<Callable<String>>();
478             l.add(new StringTask());
479             l.add(new StringTask());
480             String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
481             assertSame(TEST_STRING, result);
482             assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
483         }
484     }
485 
486     /**
487      * timed invokeAll(null) throws NPE
488      */
489     public void testTimedInvokeAll1() throws InterruptedException {
490         final ExecutorService e = new DirectExecutorService();
491         try (PoolCleaner cleaner = cleaner(e)) {
492             try {
493                 e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
494                 shouldThrow();
495             } catch (NullPointerException success) {}
496         }
497     }
498 
499     /**
500      * timed invokeAll(null time unit) throws NPE
501      */
502     public void testTimedInvokeAllNullTimeUnit() throws InterruptedException {
503         final ExecutorService e = new DirectExecutorService();
504         try (PoolCleaner cleaner = cleaner(e)) {
505             List<Callable<String>> l = new ArrayList<Callable<String>>();
506             l.add(new StringTask());
507             try {
508                 e.invokeAll(l, MEDIUM_DELAY_MS, null);
509                 shouldThrow();
510             } catch (NullPointerException success) {}
511         }
512     }
513 
514     /**
515      * timed invokeAll(empty collection) returns empty collection
516      */
517     public void testTimedInvokeAll2() throws InterruptedException {
518         final ExecutorService e = new DirectExecutorService();
519         try (PoolCleaner cleaner = cleaner(e)) {
520             List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
521             assertTrue(r.isEmpty());
522         }
523     }
524 
525     /**
526      * timed invokeAll(c) throws NPE if c has null elements
527      */
528     public void testTimedInvokeAll3() throws InterruptedException {
529         final ExecutorService e = new DirectExecutorService();
530         try (PoolCleaner cleaner = cleaner(e)) {
531             List<Callable<String>> l = new ArrayList<Callable<String>>();
532             l.add(new StringTask());
533             l.add(null);
534             try {
535                 e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
536                 shouldThrow();
537             } catch (NullPointerException success) {}
538         }
539     }
540 
541     /**
542      * get of returned element of invokeAll(c) throws exception on failed task
543      */
544     public void testTimedInvokeAll4() throws Exception {
545         final ExecutorService e = new DirectExecutorService();
546         try (PoolCleaner cleaner = cleaner(e)) {
547             List<Callable<String>> l = new ArrayList<Callable<String>>();
548             l.add(new NPETask());
549             List<Future<String>> futures =
550                 e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
551             assertEquals(1, futures.size());
552             try {
553                 futures.get(0).get();
554                 shouldThrow();
555             } catch (ExecutionException success) {
556                 assertTrue(success.getCause() instanceof NullPointerException);
557             }
558         }
559     }
560 
561     /**
562      * timed invokeAll(c) returns results of all completed tasks in c
563      */
564     public void testTimedInvokeAll5() throws Exception {
565         final ExecutorService e = new DirectExecutorService();
566         try (PoolCleaner cleaner = cleaner(e)) {
567             List<Callable<String>> l = new ArrayList<Callable<String>>();
568             l.add(new StringTask());
569             l.add(new StringTask());
570             List<Future<String>> futures =
571                 e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
572             assertEquals(2, futures.size());
573             for (Future<String> future : futures)
574                 assertSame(TEST_STRING, future.get());
575         }
576     }
577 
578     /**
579      * timed invokeAll cancels tasks not completed by timeout
580      */
581     public void testTimedInvokeAll6() throws Exception {
582         final ExecutorService e = new DirectExecutorService();
583         try (PoolCleaner cleaner = cleaner(e)) {
584             for (long timeout = timeoutMillis();;) {
585                 List<Callable<String>> tasks = new ArrayList<>();
586                 tasks.add(new StringTask("0"));
587                 tasks.add(Executors.callable(possiblyInterruptedRunnable(timeout),
588                                              TEST_STRING));
589                 tasks.add(new StringTask("2"));
590                 long startTime = System.nanoTime();
591                 List<Future<String>> futures =
592                     e.invokeAll(tasks, timeout, MILLISECONDS);
593                 assertEquals(tasks.size(), futures.size());
594                 assertTrue(millisElapsedSince(startTime) >= timeout);
595                 for (Future future : futures)
596                     assertTrue(future.isDone());
597                 try {
598                     assertEquals("0", futures.get(0).get());
599                     assertEquals(TEST_STRING, futures.get(1).get());
600                 } catch (CancellationException retryWithLongerTimeout) {
601                     // unusual delay before starting second task
602                     timeout *= 2;
603                     if (timeout >= LONG_DELAY_MS / 2)
604                         fail("expected exactly one task to be cancelled");
605                     continue;
606                 }
607                 assertTrue(futures.get(2).isCancelled());
608                 break;
609             }
610         }
611     }
612 
613 }
614