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  */
6 
7 package jsr166;
8 
9 import junit.framework.*;
10 import java.util.*;
11 import java.util.concurrent.*;
12 import static java.util.concurrent.TimeUnit.MILLISECONDS;
13 import java.util.concurrent.atomic.AtomicInteger;
14 
15 public class ScheduledExecutorSubclassTest extends JSR166TestCase {
16 
17     static class CustomTask<V> implements RunnableScheduledFuture<V> {
18         RunnableScheduledFuture<V> task;
19         volatile boolean ran;
CustomTask(RunnableScheduledFuture<V> t)20         CustomTask(RunnableScheduledFuture<V> t) { task = t; }
isPeriodic()21         public boolean isPeriodic() { return task.isPeriodic(); }
run()22         public void run() {
23             ran = true;
24             task.run();
25         }
getDelay(TimeUnit unit)26         public long getDelay(TimeUnit unit) { return task.getDelay(unit); }
compareTo(Delayed t)27         public int compareTo(Delayed t) {
28             return task.compareTo(((CustomTask)t).task);
29         }
cancel(boolean mayInterruptIfRunning)30         public boolean cancel(boolean mayInterruptIfRunning) {
31             return task.cancel(mayInterruptIfRunning);
32         }
isCancelled()33         public boolean isCancelled() { return task.isCancelled(); }
isDone()34         public boolean isDone() { return task.isDone(); }
get()35         public V get() throws InterruptedException, ExecutionException {
36             V v = task.get();
37             assertTrue(ran);
38             return v;
39         }
get(long time, TimeUnit unit)40         public V get(long time, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
41             V v = task.get(time, unit);
42             assertTrue(ran);
43             return v;
44         }
45     }
46 
47     public class CustomExecutor extends ScheduledThreadPoolExecutor {
48 
decorateTask(Runnable r, RunnableScheduledFuture<V> task)49         protected <V> RunnableScheduledFuture<V> decorateTask(Runnable r, RunnableScheduledFuture<V> task) {
50             return new CustomTask<V>(task);
51         }
52 
decorateTask(Callable<V> c, RunnableScheduledFuture<V> task)53         protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> c, RunnableScheduledFuture<V> task) {
54             return new CustomTask<V>(task);
55         }
CustomExecutor(int corePoolSize)56         CustomExecutor(int corePoolSize) { super(corePoolSize); }
CustomExecutor(int corePoolSize, RejectedExecutionHandler handler)57         CustomExecutor(int corePoolSize, RejectedExecutionHandler handler) {
58             super(corePoolSize, handler);
59         }
60 
CustomExecutor(int corePoolSize, ThreadFactory threadFactory)61         CustomExecutor(int corePoolSize, ThreadFactory threadFactory) {
62             super(corePoolSize, threadFactory);
63         }
CustomExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler)64         CustomExecutor(int corePoolSize, ThreadFactory threadFactory,
65                        RejectedExecutionHandler handler) {
66             super(corePoolSize, threadFactory, handler);
67         }
68 
69     }
70 
71     /**
72      * execute successfully executes a runnable
73      */
testExecute()74     public void testExecute() throws InterruptedException {
75         CustomExecutor p = new CustomExecutor(1);
76         final CountDownLatch done = new CountDownLatch(1);
77         final Runnable task = new CheckedRunnable() {
78             public void realRun() {
79                 done.countDown();
80             }};
81         try {
82             p.execute(task);
83             assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
84         } finally {
85             joinPool(p);
86         }
87     }
88 
89     /**
90      * delayed schedule of callable successfully executes after delay
91      */
testSchedule1()92     public void testSchedule1() throws Exception {
93         CustomExecutor p = new CustomExecutor(1);
94         final long startTime = System.nanoTime();
95         final CountDownLatch done = new CountDownLatch(1);
96         try {
97             Callable task = new CheckedCallable<Boolean>() {
98                 public Boolean realCall() {
99                     done.countDown();
100                     assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
101                     return Boolean.TRUE;
102                 }};
103             Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
104             assertSame(Boolean.TRUE, f.get());
105             assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
106             assertTrue(done.await(0L, MILLISECONDS));
107         } finally {
108             joinPool(p);
109         }
110     }
111 
112     /**
113      * delayed schedule of runnable successfully executes after delay
114      */
testSchedule3()115     public void testSchedule3() throws Exception {
116         CustomExecutor p = new CustomExecutor(1);
117         final long startTime = System.nanoTime();
118         final CountDownLatch done = new CountDownLatch(1);
119         try {
120             Runnable task = new CheckedRunnable() {
121                 public void realRun() {
122                     done.countDown();
123                     assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
124                 }};
125             Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
126             await(done);
127             assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
128             assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
129         } finally {
130             joinPool(p);
131         }
132     }
133 
134     /**
135      * scheduleAtFixedRate executes runnable after given initial delay
136      */
testSchedule4()137     public void testSchedule4() throws InterruptedException {
138         CustomExecutor p = new CustomExecutor(1);
139         final long startTime = System.nanoTime();
140         final CountDownLatch done = new CountDownLatch(1);
141         try {
142             Runnable task = new CheckedRunnable() {
143                 public void realRun() {
144                     done.countDown();
145                     assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
146                 }};
147             ScheduledFuture f =
148                 p.scheduleAtFixedRate(task, timeoutMillis(),
149                                       LONG_DELAY_MS, MILLISECONDS);
150             await(done);
151             assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
152             f.cancel(true);
153         } finally {
154             joinPool(p);
155         }
156     }
157 
158     /**
159      * scheduleWithFixedDelay executes runnable after given initial delay
160      */
testSchedule5()161     public void testSchedule5() throws InterruptedException {
162         CustomExecutor p = new CustomExecutor(1);
163         final long startTime = System.nanoTime();
164         final CountDownLatch done = new CountDownLatch(1);
165         try {
166             Runnable task = new CheckedRunnable() {
167                 public void realRun() {
168                     done.countDown();
169                     assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
170                 }};
171             ScheduledFuture f =
172                 p.scheduleWithFixedDelay(task, timeoutMillis(),
173                                          LONG_DELAY_MS, MILLISECONDS);
174             await(done);
175             assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
176             f.cancel(true);
177         } finally {
178             joinPool(p);
179         }
180     }
181 
182     static class RunnableCounter implements Runnable {
183         AtomicInteger count = new AtomicInteger(0);
run()184         public void run() { count.getAndIncrement(); }
185     }
186 
187     /**
188      * scheduleAtFixedRate executes series of tasks at given rate
189      */
testFixedRateSequence()190     public void testFixedRateSequence() throws InterruptedException {
191         CustomExecutor p = new CustomExecutor(1);
192         RunnableCounter counter = new RunnableCounter();
193         ScheduledFuture h =
194             p.scheduleAtFixedRate(counter, 0, 1, MILLISECONDS);
195         delay(SMALL_DELAY_MS);
196         h.cancel(true);
197         int c = counter.count.get();
198         // By time scaling conventions, we must have at least
199         // an execution per SHORT delay, but no more than one SHORT more
200         assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
201         assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
202         joinPool(p);
203     }
204 
205     /**
206      * scheduleWithFixedDelay executes series of tasks with given period
207      */
testFixedDelaySequence()208     public void testFixedDelaySequence() throws InterruptedException {
209         CustomExecutor p = new CustomExecutor(1);
210         RunnableCounter counter = new RunnableCounter();
211         ScheduledFuture h =
212             p.scheduleWithFixedDelay(counter, 0, 1, MILLISECONDS);
213         delay(SMALL_DELAY_MS);
214         h.cancel(true);
215         int c = counter.count.get();
216         assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
217         assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
218         joinPool(p);
219     }
220 
221     /**
222      * execute(null) throws NPE
223      */
testExecuteNull()224     public void testExecuteNull() throws InterruptedException {
225         CustomExecutor se = new CustomExecutor(1);
226         try {
227             se.execute(null);
228             shouldThrow();
229         } catch (NullPointerException success) {}
230         joinPool(se);
231     }
232 
233     /**
234      * schedule(null) throws NPE
235      */
testScheduleNull()236     public void testScheduleNull() throws InterruptedException {
237         CustomExecutor se = new CustomExecutor(1);
238         try {
239             TrackedCallable callable = null;
240             Future f = se.schedule(callable, SHORT_DELAY_MS, MILLISECONDS);
241             shouldThrow();
242         } catch (NullPointerException success) {}
243         joinPool(se);
244     }
245 
246     /**
247      * execute throws RejectedExecutionException if shutdown
248      */
testSchedule1_RejectedExecutionException()249     public void testSchedule1_RejectedExecutionException() {
250         CustomExecutor se = new CustomExecutor(1);
251         try {
252             se.shutdown();
253             se.schedule(new NoOpRunnable(),
254                         MEDIUM_DELAY_MS, MILLISECONDS);
255             shouldThrow();
256         } catch (RejectedExecutionException success) {
257         } catch (SecurityException ok) {
258         }
259 
260         joinPool(se);
261     }
262 
263     /**
264      * schedule throws RejectedExecutionException if shutdown
265      */
testSchedule2_RejectedExecutionException()266     public void testSchedule2_RejectedExecutionException() {
267         CustomExecutor se = new CustomExecutor(1);
268         try {
269             se.shutdown();
270             se.schedule(new NoOpCallable(),
271                         MEDIUM_DELAY_MS, MILLISECONDS);
272             shouldThrow();
273         } catch (RejectedExecutionException success) {
274         } catch (SecurityException ok) {
275         }
276         joinPool(se);
277     }
278 
279     /**
280      * schedule callable throws RejectedExecutionException if shutdown
281      */
testSchedule3_RejectedExecutionException()282     public void testSchedule3_RejectedExecutionException() {
283         CustomExecutor se = new CustomExecutor(1);
284         try {
285             se.shutdown();
286             se.schedule(new NoOpCallable(),
287                         MEDIUM_DELAY_MS, MILLISECONDS);
288             shouldThrow();
289         } catch (RejectedExecutionException success) {
290         } catch (SecurityException ok) {
291         }
292         joinPool(se);
293     }
294 
295     /**
296      * scheduleAtFixedRate throws RejectedExecutionException if shutdown
297      */
testScheduleAtFixedRate1_RejectedExecutionException()298     public void testScheduleAtFixedRate1_RejectedExecutionException() {
299         CustomExecutor se = new CustomExecutor(1);
300         try {
301             se.shutdown();
302             se.scheduleAtFixedRate(new NoOpRunnable(),
303                                    MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
304             shouldThrow();
305         } catch (RejectedExecutionException success) {
306         } catch (SecurityException ok) {
307         }
308         joinPool(se);
309     }
310 
311     /**
312      * scheduleWithFixedDelay throws RejectedExecutionException if shutdown
313      */
testScheduleWithFixedDelay1_RejectedExecutionException()314     public void testScheduleWithFixedDelay1_RejectedExecutionException() {
315         CustomExecutor se = new CustomExecutor(1);
316         try {
317             se.shutdown();
318             se.scheduleWithFixedDelay(new NoOpRunnable(),
319                                       MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
320             shouldThrow();
321         } catch (RejectedExecutionException success) {
322         } catch (SecurityException ok) {
323         }
324         joinPool(se);
325     }
326 
327     /**
328      * getActiveCount increases but doesn't overestimate, when a
329      * thread becomes active
330      */
testGetActiveCount()331     public void testGetActiveCount() throws InterruptedException {
332         final ThreadPoolExecutor p = new CustomExecutor(2);
333         final CountDownLatch threadStarted = new CountDownLatch(1);
334         final CountDownLatch done = new CountDownLatch(1);
335         try {
336             assertEquals(0, p.getActiveCount());
337             p.execute(new CheckedRunnable() {
338                 public void realRun() throws InterruptedException {
339                     threadStarted.countDown();
340                     assertEquals(1, p.getActiveCount());
341                     done.await();
342                 }});
343             assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
344             assertEquals(1, p.getActiveCount());
345         } finally {
346             done.countDown();
347             joinPool(p);
348         }
349     }
350 
351     /**
352      * getCompletedTaskCount increases, but doesn't overestimate,
353      * when tasks complete
354      */
testGetCompletedTaskCount()355     public void testGetCompletedTaskCount() throws InterruptedException {
356         final ThreadPoolExecutor p = new CustomExecutor(2);
357         final CountDownLatch threadStarted = new CountDownLatch(1);
358         final CountDownLatch threadProceed = new CountDownLatch(1);
359         final CountDownLatch threadDone = new CountDownLatch(1);
360         try {
361             assertEquals(0, p.getCompletedTaskCount());
362             p.execute(new CheckedRunnable() {
363                 public void realRun() throws InterruptedException {
364                     threadStarted.countDown();
365                     assertEquals(0, p.getCompletedTaskCount());
366                     threadProceed.await();
367                     threadDone.countDown();
368                 }});
369             await(threadStarted);
370             assertEquals(0, p.getCompletedTaskCount());
371             threadProceed.countDown();
372             threadDone.await();
373             long startTime = System.nanoTime();
374             while (p.getCompletedTaskCount() != 1) {
375                 if (millisElapsedSince(startTime) > LONG_DELAY_MS)
376                     fail("timed out");
377                 Thread.yield();
378             }
379         } finally {
380             joinPool(p);
381         }
382     }
383 
384     /**
385      * getCorePoolSize returns size given in constructor if not otherwise set
386      */
testGetCorePoolSize()387     public void testGetCorePoolSize() {
388         CustomExecutor p = new CustomExecutor(1);
389         assertEquals(1, p.getCorePoolSize());
390         joinPool(p);
391     }
392 
393     /**
394      * getLargestPoolSize increases, but doesn't overestimate, when
395      * multiple threads active
396      */
testGetLargestPoolSize()397     public void testGetLargestPoolSize() throws InterruptedException {
398         final int THREADS = 3;
399         final ThreadPoolExecutor p = new CustomExecutor(THREADS);
400         final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
401         final CountDownLatch done = new CountDownLatch(1);
402         try {
403             assertEquals(0, p.getLargestPoolSize());
404             for (int i = 0; i < THREADS; i++)
405                 p.execute(new CheckedRunnable() {
406                     public void realRun() throws InterruptedException {
407                         threadsStarted.countDown();
408                         done.await();
409                         assertEquals(THREADS, p.getLargestPoolSize());
410                     }});
411             assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
412             assertEquals(THREADS, p.getLargestPoolSize());
413         } finally {
414             done.countDown();
415             joinPool(p);
416             assertEquals(THREADS, p.getLargestPoolSize());
417         }
418     }
419 
420     /**
421      * getPoolSize increases, but doesn't overestimate, when threads
422      * become active
423      */
testGetPoolSize()424     public void testGetPoolSize() throws InterruptedException {
425         final ThreadPoolExecutor p = new CustomExecutor(1);
426         final CountDownLatch threadStarted = new CountDownLatch(1);
427         final CountDownLatch done = new CountDownLatch(1);
428         try {
429             assertEquals(0, p.getPoolSize());
430             p.execute(new CheckedRunnable() {
431                 public void realRun() throws InterruptedException {
432                     threadStarted.countDown();
433                     assertEquals(1, p.getPoolSize());
434                     done.await();
435                 }});
436             assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
437             assertEquals(1, p.getPoolSize());
438         } finally {
439             done.countDown();
440             joinPool(p);
441         }
442     }
443 
444     /**
445      * getTaskCount increases, but doesn't overestimate, when tasks
446      * submitted
447      */
testGetTaskCount()448     public void testGetTaskCount() throws InterruptedException {
449         final ThreadPoolExecutor p = new CustomExecutor(1);
450         final CountDownLatch threadStarted = new CountDownLatch(1);
451         final CountDownLatch done = new CountDownLatch(1);
452         final int TASKS = 5;
453         try {
454             assertEquals(0, p.getTaskCount());
455             for (int i = 0; i < TASKS; i++)
456                 p.execute(new CheckedRunnable() {
457                     public void realRun() throws InterruptedException {
458                         threadStarted.countDown();
459                         done.await();
460                     }});
461             assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
462             assertEquals(TASKS, p.getTaskCount());
463         } finally {
464             done.countDown();
465             joinPool(p);
466         }
467     }
468 
469     /**
470      * getThreadFactory returns factory in constructor if not set
471      */
testGetThreadFactory()472     public void testGetThreadFactory() {
473         ThreadFactory tf = new SimpleThreadFactory();
474         CustomExecutor p = new CustomExecutor(1, tf);
475         assertSame(tf, p.getThreadFactory());
476         joinPool(p);
477     }
478 
479     /**
480      * setThreadFactory sets the thread factory returned by getThreadFactory
481      */
testSetThreadFactory()482     public void testSetThreadFactory() {
483         ThreadFactory tf = new SimpleThreadFactory();
484         CustomExecutor p = new CustomExecutor(1);
485         p.setThreadFactory(tf);
486         assertSame(tf, p.getThreadFactory());
487         joinPool(p);
488     }
489 
490     /**
491      * setThreadFactory(null) throws NPE
492      */
testSetThreadFactoryNull()493     public void testSetThreadFactoryNull() {
494         CustomExecutor p = new CustomExecutor(1);
495         try {
496             p.setThreadFactory(null);
497             shouldThrow();
498         } catch (NullPointerException success) {
499         } finally {
500             joinPool(p);
501         }
502     }
503 
504     /**
505      * isShutdown is false before shutdown, true after
506      */
testIsShutdown()507     public void testIsShutdown() {
508         CustomExecutor p = new CustomExecutor(1);
509         try {
510             assertFalse(p.isShutdown());
511         }
512         finally {
513             try { p.shutdown(); } catch (SecurityException ok) { return; }
514         }
515         assertTrue(p.isShutdown());
516     }
517 
518     /**
519      * isTerminated is false before termination, true after
520      */
testIsTerminated()521     public void testIsTerminated() throws InterruptedException {
522         final ThreadPoolExecutor p = new CustomExecutor(1);
523         final CountDownLatch threadStarted = new CountDownLatch(1);
524         final CountDownLatch done = new CountDownLatch(1);
525         assertFalse(p.isTerminated());
526         try {
527             p.execute(new CheckedRunnable() {
528                 public void realRun() throws InterruptedException {
529                     assertFalse(p.isTerminated());
530                     threadStarted.countDown();
531                     done.await();
532                 }});
533             assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
534             assertFalse(p.isTerminating());
535             done.countDown();
536         } finally {
537             try { p.shutdown(); } catch (SecurityException ok) { return; }
538         }
539         assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
540         assertTrue(p.isTerminated());
541     }
542 
543     /**
544      * isTerminating is not true when running or when terminated
545      */
testIsTerminating()546     public void testIsTerminating() throws InterruptedException {
547         final ThreadPoolExecutor p = new CustomExecutor(1);
548         final CountDownLatch threadStarted = new CountDownLatch(1);
549         final CountDownLatch done = new CountDownLatch(1);
550         try {
551             assertFalse(p.isTerminating());
552             p.execute(new CheckedRunnable() {
553                 public void realRun() throws InterruptedException {
554                     assertFalse(p.isTerminating());
555                     threadStarted.countDown();
556                     done.await();
557                 }});
558             assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
559             assertFalse(p.isTerminating());
560             done.countDown();
561         } finally {
562             try { p.shutdown(); } catch (SecurityException ok) { return; }
563         }
564         assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
565         assertTrue(p.isTerminated());
566         assertFalse(p.isTerminating());
567     }
568 
569     /**
570      * getQueue returns the work queue, which contains queued tasks
571      */
testGetQueue()572     public void testGetQueue() throws InterruptedException {
573         ScheduledThreadPoolExecutor p = new CustomExecutor(1);
574         final CountDownLatch threadStarted = new CountDownLatch(1);
575         final CountDownLatch done = new CountDownLatch(1);
576         try {
577             ScheduledFuture[] tasks = new ScheduledFuture[5];
578             for (int i = 0; i < tasks.length; i++) {
579                 Runnable r = new CheckedRunnable() {
580                     public void realRun() throws InterruptedException {
581                         threadStarted.countDown();
582                         done.await();
583                     }};
584                 tasks[i] = p.schedule(r, 1, MILLISECONDS);
585             }
586             assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
587             BlockingQueue<Runnable> q = p.getQueue();
588             assertTrue(q.contains(tasks[tasks.length - 1]));
589             assertFalse(q.contains(tasks[0]));
590         } finally {
591             done.countDown();
592             joinPool(p);
593         }
594     }
595 
596     /**
597      * remove(task) removes queued task, and fails to remove active task
598      */
testRemove()599     public void testRemove() throws InterruptedException {
600         final ScheduledThreadPoolExecutor p = new CustomExecutor(1);
601         ScheduledFuture[] tasks = new ScheduledFuture[5];
602         final CountDownLatch threadStarted = new CountDownLatch(1);
603         final CountDownLatch done = new CountDownLatch(1);
604         try {
605             for (int i = 0; i < tasks.length; i++) {
606                 Runnable r = new CheckedRunnable() {
607                     public void realRun() throws InterruptedException {
608                         threadStarted.countDown();
609                         done.await();
610                     }};
611                 tasks[i] = p.schedule(r, 1, MILLISECONDS);
612             }
613             assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
614             BlockingQueue<Runnable> q = p.getQueue();
615             assertFalse(p.remove((Runnable)tasks[0]));
616             assertTrue(q.contains((Runnable)tasks[4]));
617             assertTrue(q.contains((Runnable)tasks[3]));
618             assertTrue(p.remove((Runnable)tasks[4]));
619             assertFalse(p.remove((Runnable)tasks[4]));
620             assertFalse(q.contains((Runnable)tasks[4]));
621             assertTrue(q.contains((Runnable)tasks[3]));
622             assertTrue(p.remove((Runnable)tasks[3]));
623             assertFalse(q.contains((Runnable)tasks[3]));
624         } finally {
625             done.countDown();
626             joinPool(p);
627         }
628     }
629 
630     /**
631      * purge removes cancelled tasks from the queue
632      */
testPurge()633     public void testPurge() throws InterruptedException {
634         CustomExecutor p = new CustomExecutor(1);
635         ScheduledFuture[] tasks = new ScheduledFuture[5];
636         for (int i = 0; i < tasks.length; i++)
637             tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
638                                   LONG_DELAY_MS, MILLISECONDS);
639         try {
640             int max = tasks.length;
641             if (tasks[4].cancel(true)) --max;
642             if (tasks[3].cancel(true)) --max;
643             // There must eventually be an interference-free point at
644             // which purge will not fail. (At worst, when queue is empty.)
645             long startTime = System.nanoTime();
646             do {
647                 p.purge();
648                 long count = p.getTaskCount();
649                 if (count == max)
650                     return;
651             } while (millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
652             fail("Purge failed to remove cancelled tasks");
653         } finally {
654             for (ScheduledFuture task : tasks)
655                 task.cancel(true);
656             joinPool(p);
657         }
658     }
659 
660     /**
661      * shutdownNow returns a list containing tasks that were not run
662      */
testShutdownNow()663     public void testShutdownNow() {
664         CustomExecutor p = new CustomExecutor(1);
665         for (int i = 0; i < 5; i++)
666             p.schedule(new SmallPossiblyInterruptedRunnable(),
667                        LONG_DELAY_MS, MILLISECONDS);
668         try {
669             List<Runnable> l = p.shutdownNow();
670             assertTrue(p.isShutdown());
671             assertEquals(5, l.size());
672         } catch (SecurityException ok) {
673             // Allowed in case test doesn't have privs
674         } finally {
675             joinPool(p);
676         }
677     }
678 
679     /**
680      * In default setting, shutdown cancels periodic but not delayed
681      * tasks at shutdown
682      */
testShutdown1()683     public void testShutdown1() throws InterruptedException {
684         CustomExecutor p = new CustomExecutor(1);
685         assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
686         assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
687 
688         ScheduledFuture[] tasks = new ScheduledFuture[5];
689         for (int i = 0; i < tasks.length; i++)
690             tasks[i] = p.schedule(new NoOpRunnable(),
691                                   SHORT_DELAY_MS, MILLISECONDS);
692         try { p.shutdown(); } catch (SecurityException ok) { return; }
693         BlockingQueue<Runnable> q = p.getQueue();
694         for (ScheduledFuture task : tasks) {
695             assertFalse(task.isDone());
696             assertFalse(task.isCancelled());
697             assertTrue(q.contains(task));
698         }
699         assertTrue(p.isShutdown());
700         assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
701         assertTrue(p.isTerminated());
702         for (ScheduledFuture task : tasks) {
703             assertTrue(task.isDone());
704             assertFalse(task.isCancelled());
705         }
706     }
707 
708     /**
709      * If setExecuteExistingDelayedTasksAfterShutdownPolicy is false,
710      * delayed tasks are cancelled at shutdown
711      */
testShutdown2()712     public void testShutdown2() throws InterruptedException {
713         CustomExecutor p = new CustomExecutor(1);
714         p.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
715         assertFalse(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
716         assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
717         ScheduledFuture[] tasks = new ScheduledFuture[5];
718         for (int i = 0; i < tasks.length; i++)
719             tasks[i] = p.schedule(new NoOpRunnable(),
720                                   SHORT_DELAY_MS, MILLISECONDS);
721         BlockingQueue q = p.getQueue();
722         assertEquals(tasks.length, q.size());
723         try { p.shutdown(); } catch (SecurityException ok) { return; }
724         assertTrue(p.isShutdown());
725         assertTrue(q.isEmpty());
726         assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
727         assertTrue(p.isTerminated());
728         for (ScheduledFuture task : tasks) {
729             assertTrue(task.isDone());
730             assertTrue(task.isCancelled());
731         }
732     }
733 
734     /**
735      * If setContinueExistingPeriodicTasksAfterShutdownPolicy is set false,
736      * periodic tasks are cancelled at shutdown
737      */
testShutdown3()738     public void testShutdown3() throws InterruptedException {
739         CustomExecutor p = new CustomExecutor(1);
740         assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
741         assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
742         p.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
743         assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
744         assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
745         long initialDelay = LONG_DELAY_MS;
746         ScheduledFuture task =
747             p.scheduleAtFixedRate(new NoOpRunnable(), initialDelay,
748                                   5, MILLISECONDS);
749         try { p.shutdown(); } catch (SecurityException ok) { return; }
750         assertTrue(p.isShutdown());
751         assertTrue(p.getQueue().isEmpty());
752         assertTrue(task.isDone());
753         assertTrue(task.isCancelled());
754         joinPool(p);
755     }
756 
757     /**
758      * if setContinueExistingPeriodicTasksAfterShutdownPolicy is true,
759      * periodic tasks are not cancelled at shutdown
760      */
testShutdown4()761     public void testShutdown4() throws InterruptedException {
762         CustomExecutor p = new CustomExecutor(1);
763         final CountDownLatch counter = new CountDownLatch(2);
764         try {
765             p.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
766             assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
767             assertTrue(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
768             final Runnable r = new CheckedRunnable() {
769                 public void realRun() {
770                     counter.countDown();
771                 }};
772             ScheduledFuture task =
773                 p.scheduleAtFixedRate(r, 1, 1, MILLISECONDS);
774             assertFalse(task.isDone());
775             assertFalse(task.isCancelled());
776             try { p.shutdown(); } catch (SecurityException ok) { return; }
777             assertFalse(task.isCancelled());
778             assertFalse(p.isTerminated());
779             assertTrue(p.isShutdown());
780             assertTrue(counter.await(SMALL_DELAY_MS, MILLISECONDS));
781             assertFalse(task.isCancelled());
782             assertTrue(task.cancel(false));
783             assertTrue(task.isDone());
784             assertTrue(task.isCancelled());
785             assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
786             assertTrue(p.isTerminated());
787         }
788         finally {
789             joinPool(p);
790         }
791     }
792 
793     /**
794      * completed submit of callable returns result
795      */
testSubmitCallable()796     public void testSubmitCallable() throws Exception {
797         ExecutorService e = new CustomExecutor(2);
798         try {
799             Future<String> future = e.submit(new StringTask());
800             String result = future.get();
801             assertSame(TEST_STRING, result);
802         } finally {
803             joinPool(e);
804         }
805     }
806 
807     /**
808      * completed submit of runnable returns successfully
809      */
testSubmitRunnable()810     public void testSubmitRunnable() throws Exception {
811         ExecutorService e = new CustomExecutor(2);
812         try {
813             Future<?> future = e.submit(new NoOpRunnable());
814             future.get();
815             assertTrue(future.isDone());
816         } finally {
817             joinPool(e);
818         }
819     }
820 
821     /**
822      * completed submit of (runnable, result) returns result
823      */
testSubmitRunnable2()824     public void testSubmitRunnable2() throws Exception {
825         ExecutorService e = new CustomExecutor(2);
826         try {
827             Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
828             String result = future.get();
829             assertSame(TEST_STRING, result);
830         } finally {
831             joinPool(e);
832         }
833     }
834 
835     /**
836      * invokeAny(null) throws NPE
837      */
testInvokeAny1()838     public void testInvokeAny1() throws Exception {
839         ExecutorService e = new CustomExecutor(2);
840         try {
841             e.invokeAny(null);
842             shouldThrow();
843         } catch (NullPointerException success) {
844         } finally {
845             joinPool(e);
846         }
847     }
848 
849     /**
850      * invokeAny(empty collection) throws IAE
851      */
testInvokeAny2()852     public void testInvokeAny2() throws Exception {
853         ExecutorService e = new CustomExecutor(2);
854         try {
855             e.invokeAny(new ArrayList<Callable<String>>());
856             shouldThrow();
857         } catch (IllegalArgumentException success) {
858         } finally {
859             joinPool(e);
860         }
861     }
862 
863     /**
864      * invokeAny(c) throws NPE if c has null elements
865      */
testInvokeAny3()866     public void testInvokeAny3() throws Exception {
867         CountDownLatch latch = new CountDownLatch(1);
868         ExecutorService e = new CustomExecutor(2);
869         List<Callable<String>> l = new ArrayList<Callable<String>>();
870         l.add(latchAwaitingStringTask(latch));
871         l.add(null);
872         try {
873             e.invokeAny(l);
874             shouldThrow();
875         } catch (NullPointerException success) {
876         } finally {
877             latch.countDown();
878             joinPool(e);
879         }
880     }
881 
882     /**
883      * invokeAny(c) throws ExecutionException if no task completes
884      */
testInvokeAny4()885     public void testInvokeAny4() throws Exception {
886         ExecutorService e = new CustomExecutor(2);
887         List<Callable<String>> l = new ArrayList<Callable<String>>();
888         l.add(new NPETask());
889         try {
890             e.invokeAny(l);
891             shouldThrow();
892         } catch (ExecutionException success) {
893             assertTrue(success.getCause() instanceof NullPointerException);
894         } finally {
895             joinPool(e);
896         }
897     }
898 
899     /**
900      * invokeAny(c) returns result of some task
901      */
testInvokeAny5()902     public void testInvokeAny5() throws Exception {
903         ExecutorService e = new CustomExecutor(2);
904         try {
905             List<Callable<String>> l = new ArrayList<Callable<String>>();
906             l.add(new StringTask());
907             l.add(new StringTask());
908             String result = e.invokeAny(l);
909             assertSame(TEST_STRING, result);
910         } finally {
911             joinPool(e);
912         }
913     }
914 
915     /**
916      * invokeAll(null) throws NPE
917      */
testInvokeAll1()918     public void testInvokeAll1() throws Exception {
919         ExecutorService e = new CustomExecutor(2);
920         try {
921             e.invokeAll(null);
922             shouldThrow();
923         } catch (NullPointerException success) {
924         } finally {
925             joinPool(e);
926         }
927     }
928 
929     /**
930      * invokeAll(empty collection) returns empty collection
931      */
testInvokeAll2()932     public void testInvokeAll2() throws Exception {
933         ExecutorService e = new CustomExecutor(2);
934         try {
935             List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
936             assertTrue(r.isEmpty());
937         } finally {
938             joinPool(e);
939         }
940     }
941 
942     /**
943      * invokeAll(c) throws NPE if c has null elements
944      */
testInvokeAll3()945     public void testInvokeAll3() throws Exception {
946         ExecutorService e = new CustomExecutor(2);
947         List<Callable<String>> l = new ArrayList<Callable<String>>();
948         l.add(new StringTask());
949         l.add(null);
950         try {
951             e.invokeAll(l);
952             shouldThrow();
953         } catch (NullPointerException success) {
954         } finally {
955             joinPool(e);
956         }
957     }
958 
959     /**
960      * get of invokeAll(c) throws exception on failed task
961      */
testInvokeAll4()962     public void testInvokeAll4() throws Exception {
963         ExecutorService e = new CustomExecutor(2);
964         List<Callable<String>> l = new ArrayList<Callable<String>>();
965         l.add(new NPETask());
966         List<Future<String>> futures = e.invokeAll(l);
967         assertEquals(1, futures.size());
968         try {
969             futures.get(0).get();
970             shouldThrow();
971         } catch (ExecutionException success) {
972             assertTrue(success.getCause() instanceof NullPointerException);
973         } finally {
974             joinPool(e);
975         }
976     }
977 
978     /**
979      * invokeAll(c) returns results of all completed tasks
980      */
testInvokeAll5()981     public void testInvokeAll5() throws Exception {
982         ExecutorService e = new CustomExecutor(2);
983         try {
984             List<Callable<String>> l = new ArrayList<Callable<String>>();
985             l.add(new StringTask());
986             l.add(new StringTask());
987             List<Future<String>> futures = e.invokeAll(l);
988             assertEquals(2, futures.size());
989             for (Future<String> future : futures)
990                 assertSame(TEST_STRING, future.get());
991         } finally {
992             joinPool(e);
993         }
994     }
995 
996     /**
997      * timed invokeAny(null) throws NPE
998      */
testTimedInvokeAny1()999     public void testTimedInvokeAny1() throws Exception {
1000         ExecutorService e = new CustomExecutor(2);
1001         try {
1002             e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
1003             shouldThrow();
1004         } catch (NullPointerException success) {
1005         } finally {
1006             joinPool(e);
1007         }
1008     }
1009 
1010     /**
1011      * timed invokeAny(,,null) throws NPE
1012      */
testTimedInvokeAnyNullTimeUnit()1013     public void testTimedInvokeAnyNullTimeUnit() throws Exception {
1014         ExecutorService e = new CustomExecutor(2);
1015         List<Callable<String>> l = new ArrayList<Callable<String>>();
1016         l.add(new StringTask());
1017         try {
1018             e.invokeAny(l, MEDIUM_DELAY_MS, null);
1019             shouldThrow();
1020         } catch (NullPointerException success) {
1021         } finally {
1022             joinPool(e);
1023         }
1024     }
1025 
1026     /**
1027      * timed invokeAny(empty collection) throws IAE
1028      */
testTimedInvokeAny2()1029     public void testTimedInvokeAny2() throws Exception {
1030         ExecutorService e = new CustomExecutor(2);
1031         try {
1032             e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
1033             shouldThrow();
1034         } catch (IllegalArgumentException success) {
1035         } finally {
1036             joinPool(e);
1037         }
1038     }
1039 
1040     /**
1041      * timed invokeAny(c) throws NPE if c has null elements
1042      */
testTimedInvokeAny3()1043     public void testTimedInvokeAny3() throws Exception {
1044         CountDownLatch latch = new CountDownLatch(1);
1045         ExecutorService e = new CustomExecutor(2);
1046         List<Callable<String>> l = new ArrayList<Callable<String>>();
1047         l.add(latchAwaitingStringTask(latch));
1048         l.add(null);
1049         try {
1050             e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
1051             shouldThrow();
1052         } catch (NullPointerException success) {
1053         } finally {
1054             latch.countDown();
1055             joinPool(e);
1056         }
1057     }
1058 
1059     /**
1060      * timed invokeAny(c) throws ExecutionException if no task completes
1061      */
testTimedInvokeAny4()1062     public void testTimedInvokeAny4() throws Exception {
1063         ExecutorService e = new CustomExecutor(2);
1064         List<Callable<String>> l = new ArrayList<Callable<String>>();
1065         l.add(new NPETask());
1066         try {
1067             e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
1068             shouldThrow();
1069         } catch (ExecutionException success) {
1070             assertTrue(success.getCause() instanceof NullPointerException);
1071         } finally {
1072             joinPool(e);
1073         }
1074     }
1075 
1076     /**
1077      * timed invokeAny(c) returns result of some task
1078      */
testTimedInvokeAny5()1079     public void testTimedInvokeAny5() throws Exception {
1080         ExecutorService e = new CustomExecutor(2);
1081         try {
1082             List<Callable<String>> l = new ArrayList<Callable<String>>();
1083             l.add(new StringTask());
1084             l.add(new StringTask());
1085             String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
1086             assertSame(TEST_STRING, result);
1087         } finally {
1088             joinPool(e);
1089         }
1090     }
1091 
1092     /**
1093      * timed invokeAll(null) throws NPE
1094      */
testTimedInvokeAll1()1095     public void testTimedInvokeAll1() throws Exception {
1096         ExecutorService e = new CustomExecutor(2);
1097         try {
1098             e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
1099             shouldThrow();
1100         } catch (NullPointerException success) {
1101         } finally {
1102             joinPool(e);
1103         }
1104     }
1105 
1106     /**
1107      * timed invokeAll(,,null) throws NPE
1108      */
testTimedInvokeAllNullTimeUnit()1109     public void testTimedInvokeAllNullTimeUnit() throws Exception {
1110         ExecutorService e = new CustomExecutor(2);
1111         List<Callable<String>> l = new ArrayList<Callable<String>>();
1112         l.add(new StringTask());
1113         try {
1114             e.invokeAll(l, MEDIUM_DELAY_MS, null);
1115             shouldThrow();
1116         } catch (NullPointerException success) {
1117         } finally {
1118             joinPool(e);
1119         }
1120     }
1121 
1122     /**
1123      * timed invokeAll(empty collection) returns empty collection
1124      */
testTimedInvokeAll2()1125     public void testTimedInvokeAll2() throws Exception {
1126         ExecutorService e = new CustomExecutor(2);
1127         try {
1128             List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
1129             assertTrue(r.isEmpty());
1130         } finally {
1131             joinPool(e);
1132         }
1133     }
1134 
1135     /**
1136      * timed invokeAll(c) throws NPE if c has null elements
1137      */
testTimedInvokeAll3()1138     public void testTimedInvokeAll3() throws Exception {
1139         ExecutorService e = new CustomExecutor(2);
1140         List<Callable<String>> l = new ArrayList<Callable<String>>();
1141         l.add(new StringTask());
1142         l.add(null);
1143         try {
1144             e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
1145             shouldThrow();
1146         } catch (NullPointerException success) {
1147         } finally {
1148             joinPool(e);
1149         }
1150     }
1151 
1152     /**
1153      * get of element of invokeAll(c) throws exception on failed task
1154      */
testTimedInvokeAll4()1155     public void testTimedInvokeAll4() throws Exception {
1156         ExecutorService e = new CustomExecutor(2);
1157         List<Callable<String>> l = new ArrayList<Callable<String>>();
1158         l.add(new NPETask());
1159         List<Future<String>> futures =
1160             e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
1161         assertEquals(1, futures.size());
1162         try {
1163             futures.get(0).get();
1164             shouldThrow();
1165         } catch (ExecutionException success) {
1166             assertTrue(success.getCause() instanceof NullPointerException);
1167         } finally {
1168             joinPool(e);
1169         }
1170     }
1171 
1172     /**
1173      * timed invokeAll(c) returns results of all completed tasks
1174      */
testTimedInvokeAll5()1175     public void testTimedInvokeAll5() throws Exception {
1176         ExecutorService e = new CustomExecutor(2);
1177         try {
1178             List<Callable<String>> l = new ArrayList<Callable<String>>();
1179             l.add(new StringTask());
1180             l.add(new StringTask());
1181             List<Future<String>> futures =
1182                 e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
1183             assertEquals(2, futures.size());
1184             for (Future<String> future : futures)
1185                 assertSame(TEST_STRING, future.get());
1186         } finally {
1187             joinPool(e);
1188         }
1189     }
1190 
1191     /**
1192      * timed invokeAll(c) cancels tasks not completed by timeout
1193      */
testTimedInvokeAll6()1194     public void testTimedInvokeAll6() throws Exception {
1195         ExecutorService e = new CustomExecutor(2);
1196         try {
1197             List<Callable<String>> l = new ArrayList<Callable<String>>();
1198             l.add(new StringTask());
1199             l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
1200             l.add(new StringTask());
1201             List<Future<String>> futures =
1202                 e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
1203             assertEquals(l.size(), futures.size());
1204             for (Future future : futures)
1205                 assertTrue(future.isDone());
1206             assertFalse(futures.get(0).isCancelled());
1207             assertTrue(futures.get(1).isCancelled());
1208         } finally {
1209             joinPool(e);
1210         }
1211     }
1212 
1213 }
1214