Automatic sources dropoff on 2020-06-10 18:32:38.095721
The change is generated with prebuilt drop tool.
Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/jsr166/ExecutorsTest.java b/jsr166/ExecutorsTest.java
new file mode 100644
index 0000000..d70ae6e
--- /dev/null
+++ b/jsr166/ExecutorsTest.java
@@ -0,0 +1,602 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class ExecutorsTest extends JSR166TestCase {
+ // android-note: Removed because the CTS runner does a bad job of
+ // retrying tests that have suite() declarations.
+ //
+ // public static void main(String[] args) {
+ // main(suite(), args);
+ // }
+ // public static Test suite() {
+ // return new TestSuite(ExecutorsTest.class);
+ // }
+
+ /**
+ * A newCachedThreadPool can execute runnables
+ */
+ public void testNewCachedThreadPool1() {
+ final ExecutorService e = Executors.newCachedThreadPool();
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ }
+ }
+
+ /**
+ * A newCachedThreadPool with given ThreadFactory can execute runnables
+ */
+ public void testNewCachedThreadPool2() {
+ final ExecutorService e = Executors.newCachedThreadPool(new SimpleThreadFactory());
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ }
+ }
+
+ /**
+ * A newCachedThreadPool with null ThreadFactory throws NPE
+ */
+ public void testNewCachedThreadPool3() {
+ try {
+ ExecutorService e = Executors.newCachedThreadPool(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A new SingleThreadExecutor can execute runnables
+ */
+ public void testNewSingleThreadExecutor1() {
+ final ExecutorService e = Executors.newSingleThreadExecutor();
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ }
+ }
+
+ /**
+ * A new SingleThreadExecutor with given ThreadFactory can execute runnables
+ */
+ public void testNewSingleThreadExecutor2() {
+ final ExecutorService e = Executors.newSingleThreadExecutor(new SimpleThreadFactory());
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ }
+ }
+
+ /**
+ * A new SingleThreadExecutor with null ThreadFactory throws NPE
+ */
+ public void testNewSingleThreadExecutor3() {
+ try {
+ ExecutorService e = Executors.newSingleThreadExecutor(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A new SingleThreadExecutor cannot be casted to concrete implementation
+ */
+ public void testCastNewSingleThreadExecutor() {
+ final ExecutorService e = Executors.newSingleThreadExecutor();
+ try (PoolCleaner cleaner = cleaner(e)) {
+ try {
+ ThreadPoolExecutor tpe = (ThreadPoolExecutor)e;
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+ }
+
+ /**
+ * A new newFixedThreadPool can execute runnables
+ */
+ public void testNewFixedThreadPool1() {
+ final ExecutorService e = Executors.newFixedThreadPool(2);
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ }
+ }
+
+ /**
+ * A new newFixedThreadPool with given ThreadFactory can execute runnables
+ */
+ public void testNewFixedThreadPool2() {
+ final ExecutorService e = Executors.newFixedThreadPool(2, new SimpleThreadFactory());
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ }
+ }
+
+ /**
+ * A new newFixedThreadPool with null ThreadFactory throws NPE
+ */
+ public void testNewFixedThreadPool3() {
+ try {
+ ExecutorService e = Executors.newFixedThreadPool(2, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A new newFixedThreadPool with 0 threads throws IAE
+ */
+ public void testNewFixedThreadPool4() {
+ try {
+ ExecutorService e = Executors.newFixedThreadPool(0);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * An unconfigurable newFixedThreadPool can execute runnables
+ */
+ public void testUnconfigurableExecutorService() {
+ final ExecutorService e = Executors.unconfigurableExecutorService(Executors.newFixedThreadPool(2));
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ }
+ }
+
+ /**
+ * unconfigurableExecutorService(null) throws NPE
+ */
+ public void testUnconfigurableExecutorServiceNPE() {
+ try {
+ ExecutorService e = Executors.unconfigurableExecutorService(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * unconfigurableScheduledExecutorService(null) throws NPE
+ */
+ public void testUnconfigurableScheduledExecutorServiceNPE() {
+ try {
+ ExecutorService e = Executors.unconfigurableScheduledExecutorService(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * a newSingleThreadScheduledExecutor successfully runs delayed task
+ */
+ public void testNewSingleThreadScheduledExecutor() throws Exception {
+ final ScheduledExecutorService p = Executors.newSingleThreadScheduledExecutor();
+ try (PoolCleaner cleaner = cleaner(p)) {
+ final CountDownLatch proceed = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ await(proceed);
+ }};
+ long startTime = System.nanoTime();
+ Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
+ timeoutMillis(), MILLISECONDS);
+ assertFalse(f.isDone());
+ proceed.countDown();
+ assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertSame(Boolean.TRUE, f.get());
+ assertTrue(f.isDone());
+ assertFalse(f.isCancelled());
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }
+ }
+
+ /**
+ * a newScheduledThreadPool successfully runs delayed task
+ */
+ public void testNewScheduledThreadPool() throws Exception {
+ final ScheduledExecutorService p = Executors.newScheduledThreadPool(2);
+ try (PoolCleaner cleaner = cleaner(p)) {
+ final CountDownLatch proceed = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ await(proceed);
+ }};
+ long startTime = System.nanoTime();
+ Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
+ timeoutMillis(), MILLISECONDS);
+ assertFalse(f.isDone());
+ proceed.countDown();
+ assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertSame(Boolean.TRUE, f.get());
+ assertTrue(f.isDone());
+ assertFalse(f.isCancelled());
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }
+ }
+
+ /**
+ * an unconfigurable newScheduledThreadPool successfully runs delayed task
+ */
+ public void testUnconfigurableScheduledExecutorService() throws Exception {
+ final ScheduledExecutorService p =
+ Executors.unconfigurableScheduledExecutorService
+ (Executors.newScheduledThreadPool(2));
+ try (PoolCleaner cleaner = cleaner(p)) {
+ final CountDownLatch proceed = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ await(proceed);
+ }};
+ long startTime = System.nanoTime();
+ Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
+ timeoutMillis(), MILLISECONDS);
+ assertFalse(f.isDone());
+ proceed.countDown();
+ assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertSame(Boolean.TRUE, f.get());
+ assertTrue(f.isDone());
+ assertFalse(f.isCancelled());
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }
+ }
+
+ /**
+ * Future.get on submitted tasks will time out if they compute too long.
+ */
+ public void testTimedCallable() throws Exception {
+ final ExecutorService[] executors = {
+ Executors.newSingleThreadExecutor(),
+ Executors.newCachedThreadPool(),
+ Executors.newFixedThreadPool(2),
+ Executors.newScheduledThreadPool(2),
+ };
+
+ final Runnable sleeper = new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ delay(LONG_DELAY_MS);
+ }};
+
+ List<Thread> threads = new ArrayList<Thread>();
+ for (final ExecutorService executor : executors) {
+ threads.add(newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Future future = executor.submit(sleeper);
+ assertFutureTimesOut(future);
+ }}));
+ }
+ for (Thread thread : threads)
+ awaitTermination(thread);
+ for (ExecutorService executor : executors)
+ joinPool(executor);
+ }
+
+ /**
+ * ThreadPoolExecutor using defaultThreadFactory has
+ * specified group, priority, daemon status, and name
+ */
+ public void testDefaultThreadFactory() throws Exception {
+ final ThreadGroup egroup = Thread.currentThread().getThreadGroup();
+ final CountDownLatch done = new CountDownLatch(1);
+ Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ try {
+ Thread current = Thread.currentThread();
+ assertTrue(!current.isDaemon());
+ assertTrue(current.getPriority() <= Thread.NORM_PRIORITY);
+ ThreadGroup g = current.getThreadGroup();
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ assertTrue(g == s.getThreadGroup());
+ else
+ assertTrue(g == egroup);
+ String name = current.getName();
+ assertTrue(name.endsWith("thread-1"));
+ } catch (SecurityException ok) {
+ // Also pass if not allowed to change setting
+ }
+ done.countDown();
+ }};
+ ExecutorService e = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(r);
+ await(done);
+ }
+ }
+
+ /**
+ * ThreadPoolExecutor using privilegedThreadFactory has
+ * specified group, priority, daemon status, name,
+ * access control context and context class loader
+ */
+ public void testPrivilegedThreadFactory() throws Exception {
+ final CountDownLatch done = new CountDownLatch(1);
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ final ThreadGroup egroup = Thread.currentThread().getThreadGroup();
+ final ClassLoader thisccl = Thread.currentThread().getContextClassLoader();
+ // android-note: Removed unsupported access controller check.
+ // final AccessControlContext thisacc = AccessController.getContext();
+ Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ Thread current = Thread.currentThread();
+ assertTrue(!current.isDaemon());
+ assertTrue(current.getPriority() <= Thread.NORM_PRIORITY);
+ ThreadGroup g = current.getThreadGroup();
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ assertTrue(g == s.getThreadGroup());
+ else
+ assertTrue(g == egroup);
+ String name = current.getName();
+ assertTrue(name.endsWith("thread-1"));
+ assertSame(thisccl, current.getContextClassLoader());
+ //assertEquals(thisacc, AccessController.getContext());
+ done.countDown();
+ }};
+ ExecutorService e = Executors.newSingleThreadExecutor(Executors.privilegedThreadFactory());
+ try (PoolCleaner cleaner = cleaner(e)) {
+ e.execute(r);
+ await(done);
+ }
+ }};
+
+ runWithPermissions(r,
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"),
+ new RuntimePermission("modifyThread"));
+ }
+
+ boolean haveCCLPermissions() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ try {
+ sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+ sm.checkPermission(new RuntimePermission("getClassLoader"));
+ } catch (AccessControlException e) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void checkCCL() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+ sm.checkPermission(new RuntimePermission("getClassLoader"));
+ }
+ }
+
+ class CheckCCL implements Callable<Object> {
+ public Object call() {
+ checkCCL();
+ return null;
+ }
+ }
+
+ /**
+ * Without class loader permissions, creating
+ * privilegedCallableUsingCurrentClassLoader throws ACE
+ */
+ public void testCreatePrivilegedCallableUsingCCLWithNoPrivs() {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ if (System.getSecurityManager() == null)
+ return;
+ try {
+ Executors.privilegedCallableUsingCurrentClassLoader(new NoOpCallable());
+ shouldThrow();
+ } catch (AccessControlException success) {}
+ }};
+
+ runWithoutPermissions(r);
+ }
+
+ /**
+ * With class loader permissions, calling
+ * privilegedCallableUsingCurrentClassLoader does not throw ACE
+ */
+ public void testPrivilegedCallableUsingCCLWithPrivs() throws Exception {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ Executors.privilegedCallableUsingCurrentClassLoader
+ (new NoOpCallable())
+ .call();
+ }};
+
+ runWithPermissions(r,
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"));
+ }
+
+ /**
+ * Without permissions, calling privilegedCallable throws ACE
+ */
+ public void testPrivilegedCallableWithNoPrivs() throws Exception {
+ // Avoid classloader-related SecurityExceptions in swingui.TestRunner
+ Executors.privilegedCallable(new CheckCCL());
+
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ if (System.getSecurityManager() == null)
+ return;
+ Callable task = Executors.privilegedCallable(new CheckCCL());
+ try {
+ task.call();
+ shouldThrow();
+ } catch (AccessControlException success) {}
+ }};
+
+ runWithoutPermissions(r);
+
+ // It seems rather difficult to test that the
+ // AccessControlContext of the privilegedCallable is used
+ // instead of its caller. Below is a failed attempt to do
+ // that, which does not work because the AccessController
+ // cannot capture the internal state of the current Policy.
+ // It would be much more work to differentiate based on,
+ // e.g. CodeSource.
+
+// final AccessControlContext[] noprivAcc = new AccessControlContext[1];
+// final Callable[] task = new Callable[1];
+
+// runWithPermissions
+// (new CheckedRunnable() {
+// public void realRun() {
+// if (System.getSecurityManager() == null)
+// return;
+// noprivAcc[0] = AccessController.getContext();
+// task[0] = Executors.privilegedCallable(new CheckCCL());
+// try {
+// AccessController.doPrivileged(new PrivilegedAction<Void>() {
+// public Void run() {
+// checkCCL();
+// return null;
+// }}, noprivAcc[0]);
+// shouldThrow();
+// } catch (AccessControlException success) {}
+// }});
+
+// runWithPermissions
+// (new CheckedRunnable() {
+// public void realRun() throws Exception {
+// if (System.getSecurityManager() == null)
+// return;
+// // Verify that we have an underprivileged ACC
+// try {
+// AccessController.doPrivileged(new PrivilegedAction<Void>() {
+// public Void run() {
+// checkCCL();
+// return null;
+// }}, noprivAcc[0]);
+// shouldThrow();
+// } catch (AccessControlException success) {}
+
+// try {
+// task[0].call();
+// shouldThrow();
+// } catch (AccessControlException success) {}
+// }},
+// new RuntimePermission("getClassLoader"),
+// new RuntimePermission("setContextClassLoader"));
+ }
+
+ /**
+ * With permissions, calling privilegedCallable succeeds
+ */
+ public void testPrivilegedCallableWithPrivs() throws Exception {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ Executors.privilegedCallable(new CheckCCL()).call();
+ }};
+
+ runWithPermissions(r,
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"));
+ }
+
+ /**
+ * callable(Runnable) returns null when called
+ */
+ public void testCallable1() throws Exception {
+ Callable c = Executors.callable(new NoOpRunnable());
+ assertNull(c.call());
+ }
+
+ /**
+ * callable(Runnable, result) returns result when called
+ */
+ public void testCallable2() throws Exception {
+ Callable c = Executors.callable(new NoOpRunnable(), one);
+ assertSame(one, c.call());
+ }
+
+ /**
+ * callable(PrivilegedAction) returns its result when called
+ */
+ public void testCallable3() throws Exception {
+ Callable c = Executors.callable(new PrivilegedAction() {
+ public Object run() { return one; }});
+ assertSame(one, c.call());
+ }
+
+ /**
+ * callable(PrivilegedExceptionAction) returns its result when called
+ */
+ public void testCallable4() throws Exception {
+ Callable c = Executors.callable(new PrivilegedExceptionAction() {
+ public Object run() { return one; }});
+ assertSame(one, c.call());
+ }
+
+ /**
+ * callable(null Runnable) throws NPE
+ */
+ public void testCallableNPE1() {
+ try {
+ Callable c = Executors.callable((Runnable) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * callable(null, result) throws NPE
+ */
+ public void testCallableNPE2() {
+ try {
+ Callable c = Executors.callable((Runnable) null, one);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * callable(null PrivilegedAction) throws NPE
+ */
+ public void testCallableNPE3() {
+ try {
+ Callable c = Executors.callable((PrivilegedAction) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * callable(null PrivilegedExceptionAction) throws NPE
+ */
+ public void testCallableNPE4() {
+ try {
+ Callable c = Executors.callable((PrivilegedExceptionAction) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+}