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.AccessControlContext;
14 import java.security.AccessControlException;
15 import java.security.AccessController;
16 import java.security.PrivilegedAction;
17 import java.security.PrivilegedExceptionAction;
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.concurrent.Callable;
21 import java.util.concurrent.CountDownLatch;
22 import java.util.concurrent.Executors;
23 import java.util.concurrent.ExecutorService;
24 import java.util.concurrent.Future;
25 import java.util.concurrent.ScheduledExecutorService;
26 import java.util.concurrent.ThreadPoolExecutor;
27 
28 import junit.framework.Test;
29 import junit.framework.TestSuite;
30 
31 public class ExecutorsTest extends JSR166TestCase {
32     // android-note: Removed because the CTS runner does a bad job of
33     // retrying tests that have suite() declarations.
34     //
35     // public static void main(String[] args) {
36     //     main(suite(), args);
37     // }
38     // public static Test suite() {
39     //     return new TestSuite(ExecutorsTest.class);
40     // }
41 
42     /**
43      * A newCachedThreadPool can execute runnables
44      */
testNewCachedThreadPool1()45     public void testNewCachedThreadPool1() {
46         final ExecutorService e = Executors.newCachedThreadPool();
47         try (PoolCleaner cleaner = cleaner(e)) {
48             e.execute(new NoOpRunnable());
49             e.execute(new NoOpRunnable());
50             e.execute(new NoOpRunnable());
51         }
52     }
53 
54     /**
55      * A newCachedThreadPool with given ThreadFactory can execute runnables
56      */
testNewCachedThreadPool2()57     public void testNewCachedThreadPool2() {
58         final ExecutorService e = Executors.newCachedThreadPool(new SimpleThreadFactory());
59         try (PoolCleaner cleaner = cleaner(e)) {
60             e.execute(new NoOpRunnable());
61             e.execute(new NoOpRunnable());
62             e.execute(new NoOpRunnable());
63         }
64     }
65 
66     /**
67      * A newCachedThreadPool with null ThreadFactory throws NPE
68      */
testNewCachedThreadPool3()69     public void testNewCachedThreadPool3() {
70         try {
71             ExecutorService e = Executors.newCachedThreadPool(null);
72             shouldThrow();
73         } catch (NullPointerException success) {}
74     }
75 
76     /**
77      * A new SingleThreadExecutor can execute runnables
78      */
testNewSingleThreadExecutor1()79     public void testNewSingleThreadExecutor1() {
80         final ExecutorService e = Executors.newSingleThreadExecutor();
81         try (PoolCleaner cleaner = cleaner(e)) {
82             e.execute(new NoOpRunnable());
83             e.execute(new NoOpRunnable());
84             e.execute(new NoOpRunnable());
85         }
86     }
87 
88     /**
89      * A new SingleThreadExecutor with given ThreadFactory can execute runnables
90      */
testNewSingleThreadExecutor2()91     public void testNewSingleThreadExecutor2() {
92         final ExecutorService e = Executors.newSingleThreadExecutor(new SimpleThreadFactory());
93         try (PoolCleaner cleaner = cleaner(e)) {
94             e.execute(new NoOpRunnable());
95             e.execute(new NoOpRunnable());
96             e.execute(new NoOpRunnable());
97         }
98     }
99 
100     /**
101      * A new SingleThreadExecutor with null ThreadFactory throws NPE
102      */
testNewSingleThreadExecutor3()103     public void testNewSingleThreadExecutor3() {
104         try {
105             ExecutorService e = Executors.newSingleThreadExecutor(null);
106             shouldThrow();
107         } catch (NullPointerException success) {}
108     }
109 
110     /**
111      * A new SingleThreadExecutor cannot be casted to concrete implementation
112      */
testCastNewSingleThreadExecutor()113     public void testCastNewSingleThreadExecutor() {
114         final ExecutorService e = Executors.newSingleThreadExecutor();
115         try (PoolCleaner cleaner = cleaner(e)) {
116             try {
117                 ThreadPoolExecutor tpe = (ThreadPoolExecutor)e;
118                 shouldThrow();
119             } catch (ClassCastException success) {}
120         }
121     }
122 
123     /**
124      * A new newFixedThreadPool can execute runnables
125      */
testNewFixedThreadPool1()126     public void testNewFixedThreadPool1() {
127         final ExecutorService e = Executors.newFixedThreadPool(2);
128         try (PoolCleaner cleaner = cleaner(e)) {
129             e.execute(new NoOpRunnable());
130             e.execute(new NoOpRunnable());
131             e.execute(new NoOpRunnable());
132         }
133     }
134 
135     /**
136      * A new newFixedThreadPool with given ThreadFactory can execute runnables
137      */
testNewFixedThreadPool2()138     public void testNewFixedThreadPool2() {
139         final ExecutorService e = Executors.newFixedThreadPool(2, new SimpleThreadFactory());
140         try (PoolCleaner cleaner = cleaner(e)) {
141             e.execute(new NoOpRunnable());
142             e.execute(new NoOpRunnable());
143             e.execute(new NoOpRunnable());
144         }
145     }
146 
147     /**
148      * A new newFixedThreadPool with null ThreadFactory throws NPE
149      */
testNewFixedThreadPool3()150     public void testNewFixedThreadPool3() {
151         try {
152             ExecutorService e = Executors.newFixedThreadPool(2, null);
153             shouldThrow();
154         } catch (NullPointerException success) {}
155     }
156 
157     /**
158      * A new newFixedThreadPool with 0 threads throws IAE
159      */
testNewFixedThreadPool4()160     public void testNewFixedThreadPool4() {
161         try {
162             ExecutorService e = Executors.newFixedThreadPool(0);
163             shouldThrow();
164         } catch (IllegalArgumentException success) {}
165     }
166 
167     /**
168      * An unconfigurable newFixedThreadPool can execute runnables
169      */
testUnconfigurableExecutorService()170     public void testUnconfigurableExecutorService() {
171         final ExecutorService e = Executors.unconfigurableExecutorService(Executors.newFixedThreadPool(2));
172         try (PoolCleaner cleaner = cleaner(e)) {
173             e.execute(new NoOpRunnable());
174             e.execute(new NoOpRunnable());
175             e.execute(new NoOpRunnable());
176         }
177     }
178 
179     /**
180      * unconfigurableExecutorService(null) throws NPE
181      */
testUnconfigurableExecutorServiceNPE()182     public void testUnconfigurableExecutorServiceNPE() {
183         try {
184             ExecutorService e = Executors.unconfigurableExecutorService(null);
185             shouldThrow();
186         } catch (NullPointerException success) {}
187     }
188 
189     /**
190      * unconfigurableScheduledExecutorService(null) throws NPE
191      */
testUnconfigurableScheduledExecutorServiceNPE()192     public void testUnconfigurableScheduledExecutorServiceNPE() {
193         try {
194             ExecutorService e = Executors.unconfigurableScheduledExecutorService(null);
195             shouldThrow();
196         } catch (NullPointerException success) {}
197     }
198 
199     /**
200      * a newSingleThreadScheduledExecutor successfully runs delayed task
201      */
testNewSingleThreadScheduledExecutor()202     public void testNewSingleThreadScheduledExecutor() throws Exception {
203         final ScheduledExecutorService p = Executors.newSingleThreadScheduledExecutor();
204         try (PoolCleaner cleaner = cleaner(p)) {
205             final CountDownLatch proceed = new CountDownLatch(1);
206             final Runnable task = new CheckedRunnable() {
207                 public void realRun() {
208                     await(proceed);
209                 }};
210             long startTime = System.nanoTime();
211             Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
212                                   timeoutMillis(), MILLISECONDS);
213             assertFalse(f.isDone());
214             proceed.countDown();
215             assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
216             assertSame(Boolean.TRUE, f.get());
217             assertTrue(f.isDone());
218             assertFalse(f.isCancelled());
219             assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
220         }
221     }
222 
223     /**
224      * a newScheduledThreadPool successfully runs delayed task
225      */
testNewScheduledThreadPool()226     public void testNewScheduledThreadPool() throws Exception {
227         final ScheduledExecutorService p = Executors.newScheduledThreadPool(2);
228         try (PoolCleaner cleaner = cleaner(p)) {
229             final CountDownLatch proceed = new CountDownLatch(1);
230             final Runnable task = new CheckedRunnable() {
231                 public void realRun() {
232                     await(proceed);
233                 }};
234             long startTime = System.nanoTime();
235             Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
236                                   timeoutMillis(), MILLISECONDS);
237             assertFalse(f.isDone());
238             proceed.countDown();
239             assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
240             assertSame(Boolean.TRUE, f.get());
241             assertTrue(f.isDone());
242             assertFalse(f.isCancelled());
243             assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
244         }
245     }
246 
247     /**
248      * an unconfigurable newScheduledThreadPool successfully runs delayed task
249      */
testUnconfigurableScheduledExecutorService()250     public void testUnconfigurableScheduledExecutorService() throws Exception {
251         final ScheduledExecutorService p =
252             Executors.unconfigurableScheduledExecutorService
253             (Executors.newScheduledThreadPool(2));
254         try (PoolCleaner cleaner = cleaner(p)) {
255             final CountDownLatch proceed = new CountDownLatch(1);
256             final Runnable task = new CheckedRunnable() {
257                 public void realRun() {
258                     await(proceed);
259                 }};
260             long startTime = System.nanoTime();
261             Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
262                                   timeoutMillis(), MILLISECONDS);
263             assertFalse(f.isDone());
264             proceed.countDown();
265             assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
266             assertSame(Boolean.TRUE, f.get());
267             assertTrue(f.isDone());
268             assertFalse(f.isCancelled());
269             assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
270         }
271     }
272 
273     /**
274      * Future.get on submitted tasks will time out if they compute too long.
275      */
testTimedCallable()276     public void testTimedCallable() throws Exception {
277         final ExecutorService[] executors = {
278             Executors.newSingleThreadExecutor(),
279             Executors.newCachedThreadPool(),
280             Executors.newFixedThreadPool(2),
281             Executors.newScheduledThreadPool(2),
282         };
283 
284         final Runnable sleeper = new CheckedInterruptedRunnable() {
285             public void realRun() throws InterruptedException {
286                 delay(LONG_DELAY_MS);
287             }};
288 
289         List<Thread> threads = new ArrayList<Thread>();
290         for (final ExecutorService executor : executors) {
291             threads.add(newStartedThread(new CheckedRunnable() {
292                 public void realRun() {
293                     Future future = executor.submit(sleeper);
294                     assertFutureTimesOut(future);
295                 }}));
296         }
297         for (Thread thread : threads)
298             awaitTermination(thread);
299         for (ExecutorService executor : executors)
300             joinPool(executor);
301     }
302 
303     /**
304      * ThreadPoolExecutor using defaultThreadFactory has
305      * specified group, priority, daemon status, and name
306      */
testDefaultThreadFactory()307     public void testDefaultThreadFactory() throws Exception {
308         final ThreadGroup egroup = Thread.currentThread().getThreadGroup();
309         final CountDownLatch done = new CountDownLatch(1);
310         Runnable r = new CheckedRunnable() {
311             public void realRun() {
312                 try {
313                     Thread current = Thread.currentThread();
314                     assertTrue(!current.isDaemon());
315                     assertTrue(current.getPriority() <= Thread.NORM_PRIORITY);
316                     ThreadGroup g = current.getThreadGroup();
317                     SecurityManager s = System.getSecurityManager();
318                     if (s != null)
319                         assertTrue(g == s.getThreadGroup());
320                     else
321                         assertTrue(g == egroup);
322                     String name = current.getName();
323                     assertTrue(name.endsWith("thread-1"));
324                 } catch (SecurityException ok) {
325                     // Also pass if not allowed to change setting
326                 }
327                 done.countDown();
328             }};
329         ExecutorService e = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
330         try (PoolCleaner cleaner = cleaner(e)) {
331             e.execute(r);
332             await(done);
333         }
334     }
335 
336     /**
337      * ThreadPoolExecutor using privilegedThreadFactory has
338      * specified group, priority, daemon status, name,
339      * access control context and context class loader
340      */
testPrivilegedThreadFactory()341     public void testPrivilegedThreadFactory() throws Exception {
342         final CountDownLatch done = new CountDownLatch(1);
343         Runnable r = new CheckedRunnable() {
344             public void realRun() throws Exception {
345                 final ThreadGroup egroup = Thread.currentThread().getThreadGroup();
346                 final ClassLoader thisccl = Thread.currentThread().getContextClassLoader();
347                 // android-note: Removed unsupported access controller check.
348                 // final AccessControlContext thisacc = AccessController.getContext();
349                 Runnable r = new CheckedRunnable() {
350                     public void realRun() {
351                         Thread current = Thread.currentThread();
352                         assertTrue(!current.isDaemon());
353                         assertTrue(current.getPriority() <= Thread.NORM_PRIORITY);
354                         ThreadGroup g = current.getThreadGroup();
355                         SecurityManager s = System.getSecurityManager();
356                         if (s != null)
357                             assertTrue(g == s.getThreadGroup());
358                         else
359                             assertTrue(g == egroup);
360                         String name = current.getName();
361                         assertTrue(name.endsWith("thread-1"));
362                         assertSame(thisccl, current.getContextClassLoader());
363                         //assertEquals(thisacc, AccessController.getContext());
364                         done.countDown();
365                     }};
366                 ExecutorService e = Executors.newSingleThreadExecutor(Executors.privilegedThreadFactory());
367                 try (PoolCleaner cleaner = cleaner(e)) {
368                     e.execute(r);
369                     await(done);
370                 }
371             }};
372 
373         runWithPermissions(r,
374                            new RuntimePermission("getClassLoader"),
375                            new RuntimePermission("setContextClassLoader"),
376                            new RuntimePermission("modifyThread"));
377     }
378 
haveCCLPermissions()379     boolean haveCCLPermissions() {
380         SecurityManager sm = System.getSecurityManager();
381         if (sm != null) {
382             try {
383                 sm.checkPermission(new RuntimePermission("setContextClassLoader"));
384                 sm.checkPermission(new RuntimePermission("getClassLoader"));
385             } catch (AccessControlException e) {
386                 return false;
387             }
388         }
389         return true;
390     }
391 
checkCCL()392     void checkCCL() {
393         SecurityManager sm = System.getSecurityManager();
394         if (sm != null) {
395             sm.checkPermission(new RuntimePermission("setContextClassLoader"));
396             sm.checkPermission(new RuntimePermission("getClassLoader"));
397         }
398     }
399 
400     class CheckCCL implements Callable<Object> {
call()401         public Object call() {
402             checkCCL();
403             return null;
404         }
405     }
406 
407     /**
408      * Without class loader permissions, creating
409      * privilegedCallableUsingCurrentClassLoader throws ACE
410      */
testCreatePrivilegedCallableUsingCCLWithNoPrivs()411     public void testCreatePrivilegedCallableUsingCCLWithNoPrivs() {
412         Runnable r = new CheckedRunnable() {
413             public void realRun() throws Exception {
414                 if (System.getSecurityManager() == null)
415                     return;
416                 try {
417                     Executors.privilegedCallableUsingCurrentClassLoader(new NoOpCallable());
418                     shouldThrow();
419                 } catch (AccessControlException success) {}
420             }};
421 
422         runWithoutPermissions(r);
423     }
424 
425     /**
426      * With class loader permissions, calling
427      * privilegedCallableUsingCurrentClassLoader does not throw ACE
428      */
testPrivilegedCallableUsingCCLWithPrivs()429     public void testPrivilegedCallableUsingCCLWithPrivs() throws Exception {
430         Runnable r = new CheckedRunnable() {
431             public void realRun() throws Exception {
432                 Executors.privilegedCallableUsingCurrentClassLoader
433                     (new NoOpCallable())
434                     .call();
435             }};
436 
437         runWithPermissions(r,
438                            new RuntimePermission("getClassLoader"),
439                            new RuntimePermission("setContextClassLoader"));
440     }
441 
442     /**
443      * Without permissions, calling privilegedCallable throws ACE
444      */
testPrivilegedCallableWithNoPrivs()445     public void testPrivilegedCallableWithNoPrivs() throws Exception {
446         // Avoid classloader-related SecurityExceptions in swingui.TestRunner
447         Executors.privilegedCallable(new CheckCCL());
448 
449         Runnable r = new CheckedRunnable() {
450             public void realRun() throws Exception {
451                 if (System.getSecurityManager() == null)
452                     return;
453                 Callable task = Executors.privilegedCallable(new CheckCCL());
454                 try {
455                     task.call();
456                     shouldThrow();
457                 } catch (AccessControlException success) {}
458             }};
459 
460         runWithoutPermissions(r);
461 
462         // It seems rather difficult to test that the
463         // AccessControlContext of the privilegedCallable is used
464         // instead of its caller.  Below is a failed attempt to do
465         // that, which does not work because the AccessController
466         // cannot capture the internal state of the current Policy.
467         // It would be much more work to differentiate based on,
468         // e.g. CodeSource.
469 
470 //         final AccessControlContext[] noprivAcc = new AccessControlContext[1];
471 //         final Callable[] task = new Callable[1];
472 
473 //         runWithPermissions
474 //             (new CheckedRunnable() {
475 //                 public void realRun() {
476 //                     if (System.getSecurityManager() == null)
477 //                         return;
478 //                     noprivAcc[0] = AccessController.getContext();
479 //                     task[0] = Executors.privilegedCallable(new CheckCCL());
480 //                     try {
481 //                         AccessController.doPrivileged(new PrivilegedAction<Void>() {
482 //                                                           public Void run() {
483 //                                                               checkCCL();
484 //                                                               return null;
485 //                                                           }}, noprivAcc[0]);
486 //                         shouldThrow();
487 //                     } catch (AccessControlException success) {}
488 //                 }});
489 
490 //         runWithPermissions
491 //             (new CheckedRunnable() {
492 //                 public void realRun() throws Exception {
493 //                     if (System.getSecurityManager() == null)
494 //                         return;
495 //                     // Verify that we have an underprivileged ACC
496 //                     try {
497 //                         AccessController.doPrivileged(new PrivilegedAction<Void>() {
498 //                                                           public Void run() {
499 //                                                               checkCCL();
500 //                                                               return null;
501 //                                                           }}, noprivAcc[0]);
502 //                         shouldThrow();
503 //                     } catch (AccessControlException success) {}
504 
505 //                     try {
506 //                         task[0].call();
507 //                         shouldThrow();
508 //                     } catch (AccessControlException success) {}
509 //                 }},
510 //              new RuntimePermission("getClassLoader"),
511 //              new RuntimePermission("setContextClassLoader"));
512     }
513 
514     /**
515      * With permissions, calling privilegedCallable succeeds
516      */
testPrivilegedCallableWithPrivs()517     public void testPrivilegedCallableWithPrivs() throws Exception {
518         Runnable r = new CheckedRunnable() {
519             public void realRun() throws Exception {
520                 Executors.privilegedCallable(new CheckCCL()).call();
521             }};
522 
523         runWithPermissions(r,
524                            new RuntimePermission("getClassLoader"),
525                            new RuntimePermission("setContextClassLoader"));
526     }
527 
528     /**
529      * callable(Runnable) returns null when called
530      */
testCallable1()531     public void testCallable1() throws Exception {
532         Callable c = Executors.callable(new NoOpRunnable());
533         assertNull(c.call());
534     }
535 
536     /**
537      * callable(Runnable, result) returns result when called
538      */
testCallable2()539     public void testCallable2() throws Exception {
540         Callable c = Executors.callable(new NoOpRunnable(), one);
541         assertSame(one, c.call());
542     }
543 
544     /**
545      * callable(PrivilegedAction) returns its result when called
546      */
testCallable3()547     public void testCallable3() throws Exception {
548         Callable c = Executors.callable(new PrivilegedAction() {
549                 public Object run() { return one; }});
550         assertSame(one, c.call());
551     }
552 
553     /**
554      * callable(PrivilegedExceptionAction) returns its result when called
555      */
testCallable4()556     public void testCallable4() throws Exception {
557         Callable c = Executors.callable(new PrivilegedExceptionAction() {
558                 public Object run() { return one; }});
559         assertSame(one, c.call());
560     }
561 
562     /**
563      * callable(null Runnable) throws NPE
564      */
testCallableNPE1()565     public void testCallableNPE1() {
566         try {
567             Callable c = Executors.callable((Runnable) null);
568             shouldThrow();
569         } catch (NullPointerException success) {}
570     }
571 
572     /**
573      * callable(null, result) throws NPE
574      */
testCallableNPE2()575     public void testCallableNPE2() {
576         try {
577             Callable c = Executors.callable((Runnable) null, one);
578             shouldThrow();
579         } catch (NullPointerException success) {}
580     }
581 
582     /**
583      * callable(null PrivilegedAction) throws NPE
584      */
testCallableNPE3()585     public void testCallableNPE3() {
586         try {
587             Callable c = Executors.callable((PrivilegedAction) null);
588             shouldThrow();
589         } catch (NullPointerException success) {}
590     }
591 
592     /**
593      * callable(null PrivilegedExceptionAction) throws NPE
594      */
testCallableNPE4()595     public void testCallableNPE4() {
596         try {
597             Callable c = Executors.callable((PrivilegedExceptionAction) null);
598             shouldThrow();
599         } catch (NullPointerException success) {}
600     }
601 
602 }
603