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