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