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