ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/ScheduledExecutorSubclassTest.java
Revision: 1.48
Committed: Mon Oct 5 21:42:48 2015 UTC (8 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.47: +20 -7 lines
Log Message:
improve testGetTaskCount

File Contents

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