• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package org.apache.harmony.tests.java.util;
19 
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.junit.Assume.assumeFalse;
25 import static org.junit.Assume.assumeTrue;
26 
27 import java.lang.Thread.UncaughtExceptionHandler;
28 import java.util.Date;
29 import java.util.Timer;
30 import java.util.TimerTask;
31 import java.util.concurrent.ConcurrentLinkedQueue;
32 import java.util.concurrent.CountDownLatch;
33 import java.util.concurrent.TimeUnit;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.atomic.AtomicLong;
36 import java.util.concurrent.atomic.AtomicReference;
37 import junit.framework.TestCase;
38 
39 import libcore.junit.util.compat.CoreCompatChangeRule;
40 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
41 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
42 
43 import org.junit.After;
44 import org.junit.Before;
45 import org.junit.Rule;
46 import org.junit.Test;
47 import org.junit.rules.TestRule;
48 import org.junit.runner.RunWith;
49 import org.junit.runners.JUnit4;
50 
51 // Android-changed: b/351566728 upgraded to JUnit4.
52 // Added @RunWith class annotation, @Before and @After annotations, and @Test
53 // annotations.
54 // Changed assert* imports.
55 @RunWith(JUnit4.class)
56 public class TimerTest {
57 
58     // Android-changed: b/351566728 need this to support added test cases.
59     @Rule
60     public final TestRule compatChangeRule = new CoreCompatChangeRule();
61 
62     int timerCounter = 0;
63 
64     private final Object sync = new Object();
65 
66     /**
67      * Warning: These tests have the possibility to leave a VM hanging if the
68      * Timer is not cancelled.
69      */
70     class TimerTestTask extends TimerTask {
71         int wasRun = 0;
72 
73         // Should we sleep for 200 ms each run()?
74         boolean sleepInRun = false;
75 
76         // Should we increment the timerCounter?
77         boolean incrementCount = false;
78 
79         // Should we terminate the timer at a specific timerCounter?
80         int terminateCount = -1;
81 
82         // The timer we belong to
83         Timer timer = null;
84 
TimerTestTask()85         public TimerTestTask() {
86         }
87 
TimerTestTask(Timer t)88         public TimerTestTask(Timer t) {
89             timer = t;
90         }
91 
run()92         public void run() {
93             synchronized (this) {
94                 wasRun++;
95             }
96             if (incrementCount) {
97                 timerCounter++;
98             }
99             if (terminateCount == timerCounter && timer != null) {
100                 timer.cancel();
101             }
102             if (sleepInRun) {
103                 try {
104                     Thread.sleep(200);
105                 } catch (InterruptedException e) {
106                     throw new RuntimeException(e);
107                 }
108             }
109             synchronized (sync) {
110                 sync.notify();
111             }
112         }
113 
wasRun()114         public synchronized int wasRun() {
115             return wasRun;
116         }
117 
sleepInRun(boolean sleepInRun)118         public void sleepInRun(boolean sleepInRun) {
119             this.sleepInRun = sleepInRun;
120         }
121 
incrementCount(boolean incrementCount)122         public void incrementCount(boolean incrementCount) {
123             this.incrementCount = incrementCount;
124         }
125 
terminateCount(int terminateCount)126         public void terminateCount(int terminateCount) {
127             this.terminateCount = terminateCount;
128         }
129     }
130 
awaitRun(TimerTestTask task)131     private void awaitRun(TimerTestTask task) throws Exception {
132         while (task.wasRun() == 0) {
133             Thread.sleep(150);
134         }
135     }
136 
137     /**
138      * java.util.Timer#Timer(boolean)
139      */
140     @Test
test_ConstructorZ()141     public void test_ConstructorZ() throws Exception {
142         Timer t = null;
143         try {
144             // Ensure a task is run
145             t = new Timer(true);
146             TimerTestTask testTask = new TimerTestTask();
147             t.schedule(testTask, 200);
148             awaitRun(testTask);
149             t.cancel();
150         } finally {
151             if (t != null)
152                 t.cancel();
153         }
154 
155     }
156 
157     /**
158      * java.util.Timer#Timer()
159      */
160     @Test
test_Constructor()161     public void test_Constructor() throws Exception {
162         Timer t = null;
163         try {
164             // Ensure a task is run
165             t = new Timer();
166             TimerTestTask testTask = new TimerTestTask();
167             t.schedule(testTask, 200);
168             awaitRun(testTask);
169             t.cancel();
170         } finally {
171             if (t != null)
172                 t.cancel();
173         }
174 
175     }
176 
177     /**
178      * java.util.Timer#Timer(String, boolean)
179      */
180     @Test
test_ConstructorSZ()181     public void test_ConstructorSZ() throws Exception {
182         Timer t = null;
183         try {
184             // Ensure a task is run
185             t = new Timer("test_ConstructorSZThread", true);
186             TimerTestTask testTask = new TimerTestTask();
187             t.schedule(testTask, 200);
188             awaitRun(testTask);
189             t.cancel();
190         } finally {
191             if (t != null)
192                 t.cancel();
193         }
194 
195         try {
196             new Timer(null, true);
197             fail();
198         } catch (NullPointerException expected) {
199         }
200 
201         try {
202             new Timer(null, false);
203             fail();
204         } catch (NullPointerException expected) {
205         }
206     }
207 
208     /**
209      * java.util.Timer#Timer(String)
210      */
211     @Test
test_ConstructorS()212     public void test_ConstructorS() throws Exception {
213         Timer t = null;
214         try {
215             // Ensure a task is run
216             t = new Timer("test_ConstructorSThread");
217             TimerTestTask testTask = new TimerTestTask();
218             t.schedule(testTask, 200);
219             awaitRun(testTask);
220             t.cancel();
221         } finally {
222             if (t != null)
223                 t.cancel();
224         }
225 
226         try {
227             new Timer(null);
228             fail();
229         } catch (NullPointerException expected) {
230         }
231     }
232 
233     /**
234      * java.util.Timer#cancel()
235      */
236     @Test
test_cancel()237     public void test_cancel() throws Exception {
238         Timer t = null;
239         try {
240             // Ensure a task throws an IllegalStateException after cancelled
241             t = new Timer();
242             TimerTestTask testTask = new TimerTestTask();
243             t.cancel();
244             try {
245                 t.schedule(testTask, 100, 200);
246                 fail("Scheduling a task after Timer.cancel() should throw exception");
247             } catch (IllegalStateException expected) {
248             }
249 
250             // Ensure a task is run but not after cancel
251             t = new Timer();
252             testTask = new TimerTestTask();
253             t.schedule(testTask, 100, 500);
254             awaitRun(testTask);
255             t.cancel();
256             synchronized (sync) {
257                 sync.wait(500);
258             }
259             assertEquals("TimerTask.run() method should not have been called after cancel",
260                     1, testTask.wasRun());
261 
262             // Ensure you can call cancel more than once
263             t = new Timer();
264             testTask = new TimerTestTask();
265             t.schedule(testTask, 100, 500);
266             awaitRun(testTask);
267             t.cancel();
268             t.cancel();
269             t.cancel();
270             synchronized (sync) {
271                 sync.wait(500);
272             }
273             assertEquals("TimerTask.run() method should not have been called after cancel",
274                     1, testTask.wasRun());
275 
276             // Ensure that a call to cancel from within a timer ensures no more
277             // run
278             t = new Timer();
279             testTask = new TimerTestTask(t);
280             testTask.incrementCount(true);
281             testTask.terminateCount(5); // Terminate after 5 runs
282             t.schedule(testTask, 100, 100);
283             synchronized (sync) {
284                 sync.wait(200);
285                 assertEquals(1, testTask.wasRun());
286                 sync.wait(200);
287                 assertEquals(2, testTask.wasRun());
288                 sync.wait(200);
289                 assertEquals(3, testTask.wasRun());
290                 sync.wait(200);
291                 assertEquals(4, testTask.wasRun());
292                 sync.wait(200);
293                 assertEquals(5, testTask.wasRun());
294                 sync.wait(200);
295                 assertEquals(5, testTask.wasRun());
296             }
297             t.cancel();
298             Thread.sleep(200);
299         } finally {
300             if (t != null)
301                 t.cancel();
302         }
303 
304     }
305 
306     /**
307      * java.util.Timer#purge()
308      */
309     @Test
test_purge()310     public void test_purge() throws Exception {
311         Timer t = null;
312         try {
313             t = new Timer();
314             assertEquals(0, t.purge());
315 
316             TimerTestTask[] tasks = new TimerTestTask[100];
317             int[] delayTime = { 50, 80, 20, 70, 40, 10, 90, 30, 60 };
318 
319             int j = 0;
320             for (int i = 0; i < 100; i++) {
321                 tasks[i] = new TimerTestTask();
322                 t.schedule(tasks[i], delayTime[j++], 200);
323                 if (j == 9) {
324                     j = 0;
325                 }
326             }
327 
328             for (int i = 0; i < 50; i++) {
329                 tasks[i].cancel();
330             }
331 
332             assertTrue(t.purge() <= 50);
333             assertEquals(0, t.purge());
334         } finally {
335             if (t != null) {
336                 t.cancel();
337             }
338         }
339     }
340 
341     /**
342      * java.util.Timer#schedule(java.util.TimerTask, java.util.Date)
343      */
344     @Test
test_scheduleLjava_util_TimerTaskLjava_util_Date()345     public void test_scheduleLjava_util_TimerTaskLjava_util_Date() throws Exception {
346         Timer t = null;
347         try {
348             // Ensure a Timer throws an IllegalStateException after cancelled
349             t = new Timer();
350             TimerTestTask testTask = new TimerTestTask();
351             Date d = new Date(System.currentTimeMillis() + 100);
352             t.cancel();
353             try {
354                 t.schedule(testTask, d);
355                 fail("Scheduling a task after Timer.cancel() should throw exception");
356             } catch (IllegalStateException expected) {
357             }
358 
359             // Ensure a Timer throws an IllegalStateException if task already
360             // cancelled
361             t = new Timer();
362             testTask = new TimerTestTask();
363             d = new Date(System.currentTimeMillis() + 100);
364             testTask.cancel();
365             try {
366                 t.schedule(testTask, d);
367                 fail("Scheduling a task after cancelling it should throw exception");
368             } catch (IllegalStateException expected) {
369             }
370             t.cancel();
371 
372             // Ensure a Timer throws an IllegalArgumentException if delay is
373             // negative
374             t = new Timer();
375             testTask = new TimerTestTask();
376             d = new Date(-100);
377             try {
378                 t.schedule(testTask, d);
379                 fail("Scheduling a task with negative date should throw IllegalArgumentException");
380             } catch (IllegalArgumentException expected) {
381             }
382             t.cancel();
383 
384             // Ensure a Timer throws a NullPointerException if the task is null
385             t = new Timer();
386             d = new Date(System.currentTimeMillis() + 100);
387             try {
388                 t.schedule(null, d);
389                 fail("Scheduling a null task should throw NullPointerException");
390             } catch (NullPointerException expected) {
391             }
392             t.cancel();
393 
394             // Ensure a Timer throws a NullPointerException if the date is null
395             t = new Timer();
396             testTask = new TimerTestTask();
397             try {
398                 t.schedule(testTask, null);
399                 fail("Scheduling a null date should throw NullPointerException");
400             } catch (NullPointerException expected) {
401             }
402             t.cancel();
403 
404             // Ensure proper sequence of exceptions
405             t = new Timer();
406             d = new Date(-100);
407             try {
408                 t.schedule(null, d);
409                 fail("Scheduling a null task with negative date should throw IllegalArgumentException first");
410             } catch (IllegalArgumentException expected) {
411             }
412             t.cancel();
413 
414             // Ensure a task is run
415             t = new Timer();
416             testTask = new TimerTestTask();
417             d = new Date(System.currentTimeMillis() + 200);
418             t.schedule(testTask, d);
419             awaitRun(testTask);
420             t.cancel();
421 
422             // Ensure multiple tasks are run
423             t = new Timer();
424             testTask = new TimerTestTask();
425             testTask.incrementCount(true);
426             d = new Date(System.currentTimeMillis() + 100);
427             t.schedule(testTask, d);
428             testTask = new TimerTestTask();
429             testTask.incrementCount(true);
430             d = new Date(System.currentTimeMillis() + 150);
431             t.schedule(testTask, d);
432             testTask = new TimerTestTask();
433             testTask.incrementCount(true);
434             d = new Date(System.currentTimeMillis() + 70);
435             t.schedule(testTask, d);
436             testTask = new TimerTestTask();
437             testTask.incrementCount(true);
438             d = new Date(System.currentTimeMillis() + 10);
439             t.schedule(testTask, d);
440             Thread.sleep(400);
441             assertTrue("Multiple tasks should have incremented counter 4 times not "
442                     + timerCounter, timerCounter == 4);
443             t.cancel();
444         } finally {
445             if (t != null)
446                 t.cancel();
447         }
448     }
449 
450     /**
451      * java.util.Timer#schedule(java.util.TimerTask, long)
452      */
453     @Test
test_scheduleLjava_util_TimerTaskJ()454     public void test_scheduleLjava_util_TimerTaskJ() throws Exception {
455         Timer t = null;
456         try {
457             // Ensure a Timer throws an IllegalStateException after cancelled
458             t = new Timer();
459             TimerTestTask testTask = new TimerTestTask();
460             t.cancel();
461             try {
462                 t.schedule(testTask, 100);
463                 fail("Scheduling a task after Timer.cancel() should throw exception");
464             } catch (IllegalStateException expected) {
465             }
466 
467             // Ensure a Timer throws an IllegalStateException if task already
468             // cancelled
469             t = new Timer();
470             testTask = new TimerTestTask();
471             testTask.cancel();
472             try {
473                 t.schedule(testTask, 100);
474                 fail("Scheduling a task after cancelling it should throw exception");
475             } catch (IllegalStateException expected) {
476             }
477             t.cancel();
478 
479             // Ensure a Timer throws an IllegalArgumentException if delay is
480             // negative
481             t = new Timer();
482             testTask = new TimerTestTask();
483             try {
484                 t.schedule(testTask, -100);
485                 fail("Scheduling a task with negative delay should throw IllegalArgumentException");
486             } catch (IllegalArgumentException expected) {
487             }
488             t.cancel();
489 
490             // Ensure a Timer throws a NullPointerException if the task is null
491             t = new Timer();
492             try {
493                 t.schedule(null, 10);
494                 fail("Scheduling a null task should throw NullPointerException");
495             } catch (NullPointerException expected) {
496             }
497             t.cancel();
498 
499             // Ensure proper sequence of exceptions
500             t = new Timer();
501             try {
502                 t.schedule(null, -10);
503                 fail("Scheduling a null task with negative delays should throw IllegalArgumentException first");
504             } catch (IllegalArgumentException expected) {
505             }
506             t.cancel();
507 
508             // Ensure a task is run
509             t = new Timer();
510             testTask = new TimerTestTask();
511             t.schedule(testTask, 200);
512             awaitRun(testTask);
513             t.cancel();
514 
515             // Ensure multiple tasks are run
516             t = new Timer();
517             testTask = new TimerTestTask();
518             testTask.incrementCount(true);
519             t.schedule(testTask, 100);
520             testTask = new TimerTestTask();
521             testTask.incrementCount(true);
522             t.schedule(testTask, 150);
523             testTask = new TimerTestTask();
524             testTask.incrementCount(true);
525             t.schedule(testTask, 70);
526             testTask = new TimerTestTask();
527             testTask.incrementCount(true);
528             t.schedule(testTask, 10);
529             Thread.sleep(400);
530             assertTrue("Multiple tasks should have incremented counter 4 times not "
531                     + timerCounter, timerCounter == 4);
532             t.cancel();
533         } finally {
534             if (t != null)
535                 t.cancel();
536         }
537     }
538 
539     /**
540      * java.util.Timer#schedule(java.util.TimerTask, long, long)
541      */
542     @Test
test_scheduleLjava_util_TimerTaskJJ()543     public void test_scheduleLjava_util_TimerTaskJJ() throws Exception {
544         Timer t = null;
545         try {
546             // Ensure a Timer throws an IllegalStateException after cancelled
547             t = new Timer();
548             TimerTestTask testTask = new TimerTestTask();
549             t.cancel();
550             try {
551                 t.schedule(testTask, 100, 100);
552                 fail("Scheduling a task after Timer.cancel() should throw exception");
553             } catch (IllegalStateException expected) {
554             }
555 
556             // Ensure a Timer throws an IllegalStateException if task already
557             // cancelled
558             t = new Timer();
559             testTask = new TimerTestTask();
560             testTask.cancel();
561             try {
562                 t.schedule(testTask, 100, 100);
563                 fail("Scheduling a task after cancelling it should throw exception");
564             } catch (IllegalStateException expected) {
565             }
566             t.cancel();
567 
568             // Ensure a Timer throws an IllegalArgumentException if delay is
569             // negative
570             t = new Timer();
571             testTask = new TimerTestTask();
572             try {
573                 t.schedule(testTask, -100, 100);
574                 fail("Scheduling a task with negative delay should throw IllegalArgumentException");
575             } catch (IllegalArgumentException expected) {
576             }
577             t.cancel();
578 
579             // Ensure a Timer throws an IllegalArgumentException if period is
580             // negative
581             t = new Timer();
582             testTask = new TimerTestTask();
583             try {
584                 t.schedule(testTask, 100, -100);
585                 fail("Scheduling a task with negative period should throw IllegalArgumentException");
586             } catch (IllegalArgumentException expected) {
587             }
588             t.cancel();
589 
590             // Ensure a Timer throws an IllegalArgumentException if period is
591             // zero
592             t = new Timer();
593             testTask = new TimerTestTask();
594             try {
595                 t.schedule(testTask, 100, 0);
596                 fail("Scheduling a task with 0 period should throw IllegalArgumentException");
597             } catch (IllegalArgumentException expected) {
598             }
599             t.cancel();
600 
601             // Ensure a Timer throws a NullPointerException if the task is null
602             t = new Timer();
603             try {
604                 t.schedule(null, 10, 10);
605                 fail("Scheduling a null task should throw NullPointerException");
606             } catch (NullPointerException expected) {
607             }
608             t.cancel();
609 
610             // Ensure proper sequence of exceptions
611             t = new Timer();
612             try {
613                 t.schedule(null, -10, -10);
614                 fail("Scheduling a null task with negative delays should throw IllegalArgumentException first");
615             } catch (IllegalArgumentException expected) {
616             }
617             t.cancel();
618 
619             // Ensure a task is run at least twice
620             t = new Timer();
621             testTask = new TimerTestTask();
622             t.schedule(testTask, 100, 100);
623             Thread.sleep(400);
624             assertTrue("TimerTask.run() method should have been called at least twice ("
625                     + testTask.wasRun() + ")", testTask.wasRun() >= 2);
626             t.cancel();
627 
628             // Ensure multiple tasks are run
629             t = new Timer();
630             testTask = new TimerTestTask();
631             testTask.incrementCount(true);
632             t.schedule(testTask, 100, 100); // at least 9 times
633             testTask = new TimerTestTask();
634             testTask.incrementCount(true);
635             t.schedule(testTask, 200, 100); // at least 7 times
636             testTask = new TimerTestTask();
637             testTask.incrementCount(true);
638             t.schedule(testTask, 300, 200); // at least 4 times
639             testTask = new TimerTestTask();
640             testTask.incrementCount(true);
641             t.schedule(testTask, 100, 200); // at least 4 times
642             Thread.sleep(1200); // Allowed more room for error
643             assertTrue("Multiple tasks should have incremented counter 24 times not "
644                     + timerCounter, timerCounter >= 24);
645             t.cancel();
646         } finally {
647             if (t != null)
648                 t.cancel();
649         }
650     }
651 
652     /**
653      * java.util.Timer#schedule(java.util.TimerTask, java.util.Date,
654      *        long)
655      */
656     @Test
test_scheduleLjava_util_TimerTaskLjava_util_DateJ()657     public void test_scheduleLjava_util_TimerTaskLjava_util_DateJ() throws Exception {
658         Timer t = null;
659         try {
660             // Ensure a Timer throws an IllegalStateException after cancelled
661             t = new Timer();
662             TimerTestTask testTask = new TimerTestTask();
663             Date d = new Date(System.currentTimeMillis() + 100);
664             t.cancel();
665             try {
666                 t.schedule(testTask, d, 100);
667                 fail("Scheduling a task after Timer.cancel() should throw exception");
668             } catch (IllegalStateException expected) {
669             }
670 
671             // Ensure a Timer throws an IllegalStateException if task already
672             // cancelled
673             t = new Timer();
674             d = new Date(System.currentTimeMillis() + 100);
675             testTask = new TimerTestTask();
676             testTask.cancel();
677             try {
678                 t.schedule(testTask, d, 100);
679                 fail("Scheduling a task after cancelling it should throw exception");
680             } catch (IllegalStateException expected) {
681             }
682             t.cancel();
683 
684             // Ensure a Timer throws an IllegalArgumentException if delay is
685             // negative
686             t = new Timer();
687             d = new Date(-100);
688             testTask = new TimerTestTask();
689             try {
690                 t.schedule(testTask, d, 100);
691                 fail("Scheduling a task with negative delay should throw IllegalArgumentException");
692             } catch (IllegalArgumentException expected) {
693             }
694             t.cancel();
695 
696             // Ensure a Timer throws an IllegalArgumentException if period is
697             // negative
698             t = new Timer();
699             d = new Date(System.currentTimeMillis() + 100);
700             testTask = new TimerTestTask();
701             try {
702                 t.schedule(testTask, d, -100);
703                 fail("Scheduling a task with negative period should throw IllegalArgumentException");
704             } catch (IllegalArgumentException expected) {
705             }
706             t.cancel();
707 
708             // Ensure a Timer throws a NullPointerException if the task is null
709             t = new Timer();
710             d = new Date(System.currentTimeMillis() + 100);
711             try {
712                 t.schedule(null, d, 10);
713                 fail("Scheduling a null task should throw NullPointerException");
714             } catch (NullPointerException expected) {
715             }
716             t.cancel();
717 
718             // Ensure a Timer throws a NullPointerException if the date is null
719             t = new Timer();
720             testTask = new TimerTestTask();
721             try {
722                 t.schedule(testTask, null, 10);
723                 fail("Scheduling a null task should throw NullPointerException");
724             } catch (NullPointerException expected) {
725             }
726             t.cancel();
727 
728             // Ensure proper sequence of exceptions
729             t = new Timer();
730             d = new Date(-100);
731             try {
732                 t.schedule(null, d, 10);
733                 fail("Scheduling a null task with negative dates should throw IllegalArgumentException first");
734             } catch (IllegalArgumentException expected) {
735             }
736             t.cancel();
737 
738             // Ensure a task is run at least twice
739             t = new Timer();
740             d = new Date(System.currentTimeMillis() + 100);
741             testTask = new TimerTestTask();
742             t.schedule(testTask, d, 100);
743             Thread.sleep(800);
744             assertTrue("TimerTask.run() method should have been called at least twice ("
745                     + testTask.wasRun() + ")", testTask.wasRun() >= 2);
746             t.cancel();
747 
748             // Ensure multiple tasks are run
749             t = new Timer();
750             testTask = new TimerTestTask();
751             testTask.incrementCount(true);
752             d = new Date(System.currentTimeMillis() + 100);
753             t.schedule(testTask, d, 200); // at least 4 times
754             testTask = new TimerTestTask();
755             testTask.incrementCount(true);
756             d = new Date(System.currentTimeMillis() + 300);
757             t.schedule(testTask, d, 200); // at least 4 times
758             testTask = new TimerTestTask();
759             testTask.incrementCount(true);
760             d = new Date(System.currentTimeMillis() + 500);
761             t.schedule(testTask, d, 400); // at least 2 times
762             testTask = new TimerTestTask();
763             testTask.incrementCount(true);
764             d = new Date(System.currentTimeMillis() + 100);
765             t.schedule(testTask, d, 400); // at least 2 times
766             Thread.sleep(3000);
767             assertTrue("Multiple tasks should have incremented counter 12 times not "
768                     + timerCounter, timerCounter >= 12);
769             t.cancel();
770         } finally {
771             if (t != null)
772                 t.cancel();
773         }
774     }
775 
776     /**
777      * java.util.Timer#scheduleAtFixedRate(java.util.TimerTask, long,
778      *        long)
779      */
780     @Test
test_scheduleAtFixedRateLjava_util_TimerTaskJJ()781     public void test_scheduleAtFixedRateLjava_util_TimerTaskJJ() throws Exception {
782         Timer t = null;
783         try {
784             // Ensure a Timer throws an IllegalStateException after cancelled
785             t = new Timer();
786             TimerTestTask testTask = new TimerTestTask();
787             t.cancel();
788             try {
789                 t.scheduleAtFixedRate(testTask, 100, 100);
790                 fail("scheduleAtFixedRate after Timer.cancel() should throw exception");
791             } catch (IllegalStateException expected) {
792             }
793 
794             // Ensure a Timer throws an IllegalArgumentException if delay is
795             // negative
796             t = new Timer();
797             testTask = new TimerTestTask();
798             try {
799                 t.scheduleAtFixedRate(testTask, -100, 100);
800                 fail("scheduleAtFixedRate with negative delay should throw IllegalArgumentException");
801             } catch (IllegalArgumentException expected) {
802             }
803             t.cancel();
804 
805             // Ensure a Timer throws an IllegalArgumentException if period is
806             // negative
807             t = new Timer();
808             testTask = new TimerTestTask();
809             try {
810                 t.scheduleAtFixedRate(testTask, 100, -100);
811                 fail("scheduleAtFixedRate with negative period should throw IllegalArgumentException");
812             } catch (IllegalArgumentException expected) {
813             }
814             t.cancel();
815 
816             // Ensure a task is run at least twice
817             t = new Timer();
818             testTask = new TimerTestTask();
819             t.scheduleAtFixedRate(testTask, 100, 100);
820             Thread.sleep(400);
821             assertTrue("TimerTask.run() method should have been called at least twice ("
822                     + testTask.wasRun() + ")", testTask.wasRun() >= 2);
823             t.cancel();
824 
825             class SlowThenFastTask extends TimerTask {
826                 int wasRun = 0;
827 
828                 long startedAt;
829 
830                 long lastDelta;
831 
832                 public void run() {
833                     if (wasRun == 0)
834                         startedAt = System.currentTimeMillis();
835                     lastDelta = System.currentTimeMillis()
836                             - (startedAt + (100 * wasRun));
837                     wasRun++;
838                     if (wasRun == 2) {
839                         try {
840                             Thread.sleep(200);
841                         } catch (InterruptedException e) {
842                             throw new RuntimeException(e);
843                         }
844                     }
845                 }
846 
847                 public long lastDelta() {
848                     return lastDelta;
849                 }
850 
851                 public int wasRun() {
852                     return wasRun;
853                 }
854             }
855 
856             // Ensure multiple tasks are run
857             t = new Timer();
858             SlowThenFastTask slowThenFastTask = new SlowThenFastTask();
859 
860             // at least 9 times even when asleep
861             t.scheduleAtFixedRate(slowThenFastTask, 100, 100);
862             Thread.sleep(1000);
863             long lastDelta = slowThenFastTask.lastDelta();
864             assertTrue("Fixed Rate Schedule should catch up, but is off by "
865                     + lastDelta + " ms", slowThenFastTask.lastDelta < 300);
866             t.cancel();
867         } finally {
868             if (t != null)
869                 t.cancel();
870         }
871     }
872 
873     // Android-changed: b/351566728 added this test case to test new behavior.
874     @DisableCompatChanges({Timer.SKIP_MULTIPLE_MISSED_PERIODIC_TASKS})
875     @Test
test_scheduleAtFixedRateLjava_util_TimerTaskJJ_SkipMultipleMissedFixedRateTasks_oldBehavior()876     public void test_scheduleAtFixedRateLjava_util_TimerTaskJJ_SkipMultipleMissedFixedRateTasks_oldBehavior() throws Exception {
877         assumeFalse(Timer.skipMultipleMissedPeriodicTasks());
878         Timer t = null;
879         final ConcurrentLinkedQueue<Long> executionTimes =
880                 new ConcurrentLinkedQueue<>();
881         try {
882             final CountDownLatch latch = new CountDownLatch(10);
883 
884             class SlowThenFastTask extends TimerTask {
885                 boolean firstRun = true;
886 
887                 public void run() {
888                     if (firstRun) {
889                         firstRun = false;
890                         try {
891                             // Sleep through four periods
892                             Thread.sleep(400);
893                         } catch (InterruptedException e) {
894                             throw new RuntimeException(e);
895                         }
896                     }
897                     executionTimes.add(System.currentTimeMillis());
898                     latch.countDown();
899                 }
900             }
901 
902             t = new Timer();
903             SlowThenFastTask slowThenFastTask = new SlowThenFastTask();
904 
905             t.scheduleAtFixedRate(slowThenFastTask, 100, 100);
906             assertTrue("Fixed rate tasks didn't run 10 times within 10 periods;"
907                 + " times: " + executionTimes,
908                 latch.await(1_100, TimeUnit.MILLISECONDS));
909             t.cancel();
910         } finally {
911             if (t != null) {
912                 t.cancel();
913             }
914         }
915     }
916 
917     // Android-changed: b/351566728 added this test case to test new behavior.
918     @EnableCompatChanges({Timer.SKIP_MULTIPLE_MISSED_PERIODIC_TASKS})
919     @Test
test_scheduleAtFixedRateLjava_util_TimerTaskJJ_SkipMultipleMissedFixedRateTasks_newBehavior()920     public void test_scheduleAtFixedRateLjava_util_TimerTaskJJ_SkipMultipleMissedFixedRateTasks_newBehavior() throws Exception {
921         assumeTrue(Timer.skipMultipleMissedPeriodicTasks());
922         Timer t = null;
923         final ConcurrentLinkedQueue<Long> executionTimes =
924                 new ConcurrentLinkedQueue<>();
925         try {
926             final CountDownLatch latch = new CountDownLatch(6);
927 
928             class SlowThenFastTask extends TimerTask {
929                 boolean firstRun = true;
930 
931                 public void run() {
932                     if (firstRun) {
933                         firstRun = false;
934                         try {
935                             // Sleep through four periods
936                             Thread.sleep(400);
937                         } catch (InterruptedException e) {
938                             throw new RuntimeException(e);
939                         }
940                     }
941                     executionTimes.add(System.currentTimeMillis());
942                     latch.countDown();
943                 }
944             }
945 
946             t = new Timer();
947             SlowThenFastTask slowThenFastTask = new SlowThenFastTask();
948 
949             long startedAt = System.currentTimeMillis();
950             t.scheduleAtFixedRate(slowThenFastTask, 100, 100);
951             latch.await(1_000, TimeUnit.MILLISECONDS);
952             long finishedAt = System.currentTimeMillis();
953             assertTrue("Fixed rate schedule ran too fast, took only: "
954                     + (finishedAt - startedAt) + " ms;"
955                     + " times: " + executionTimes,
956                     finishedAt - startedAt > 700);
957             t.cancel();
958         } finally {
959             if (t != null) {
960                 t.cancel();
961             }
962         }
963     }
964 
965     /**
966      * java.util.Timer#scheduleAtFixedRate(java.util.TimerTask,
967      *        java.util.Date, long)
968      */
969     @Test
test_scheduleAtFixedRateLjava_util_TimerTaskLjava_util_DateJ()970     public void test_scheduleAtFixedRateLjava_util_TimerTaskLjava_util_DateJ() throws Exception {
971         Timer t = null;
972         try {
973             // Ensure a Timer throws an IllegalStateException after cancelled
974             t = new Timer();
975             TimerTestTask testTask = new TimerTestTask();
976             t.cancel();
977             Date d = new Date(System.currentTimeMillis() + 100);
978             try {
979                 t.scheduleAtFixedRate(testTask, d, 100);
980                 fail("scheduleAtFixedRate after Timer.cancel() should throw exception");
981             } catch (IllegalStateException expected) {
982             }
983 
984             // Ensure a Timer throws an IllegalArgumentException if delay is
985             // negative
986             t = new Timer();
987             testTask = new TimerTestTask();
988             d = new Date(-100);
989             try {
990                 t.scheduleAtFixedRate(testTask, d, 100);
991                 fail("scheduleAtFixedRate with negative Date should throw IllegalArgumentException");
992             } catch (IllegalArgumentException expected) {
993             }
994             t.cancel();
995 
996             // Ensure a Timer throws an IllegalArgumentException if period is
997             // negative
998             t = new Timer();
999             testTask = new TimerTestTask();
1000             try {
1001                 t.scheduleAtFixedRate(testTask, d, -100);
1002                 fail("scheduleAtFixedRate with negative period should throw IllegalArgumentException");
1003             } catch (IllegalArgumentException expected) {
1004             }
1005             t.cancel();
1006 
1007             // Ensure a Timer throws an NullPointerException if date is Null
1008             t = new Timer();
1009             testTask = new TimerTestTask();
1010             try {
1011                 t.scheduleAtFixedRate(testTask, null, 100);
1012                 fail("scheduleAtFixedRate with null date should throw NullPointerException");
1013             } catch (NullPointerException expected) {
1014             }
1015             t.cancel();
1016 
1017             // Ensure proper sequence of exceptions
1018             t = new Timer();
1019             d = new Date(-100);
1020             try {
1021                 t.scheduleAtFixedRate(null, d, 10);
1022                 fail("Scheduling a null task with negative date should throw IllegalArgumentException first");
1023             } catch (IllegalArgumentException expected) {
1024             }
1025             t.cancel();
1026 
1027             // Ensure proper sequence of exceptions
1028             t = new Timer();
1029             try {
1030                 t.scheduleAtFixedRate(null, null, -10);
1031                 fail("Scheduling a null task & null date & negative period should throw IllegalArgumentException first");
1032             } catch (IllegalArgumentException expected) {
1033             }
1034             t.cancel();
1035 
1036             // Ensure a task is run at least twice
1037             t = new Timer();
1038             testTask = new TimerTestTask();
1039             d = new Date(System.currentTimeMillis() + 100);
1040             t.scheduleAtFixedRate(testTask, d, 100);
1041             Thread.sleep(400);
1042             assertTrue("TimerTask.run() method should have been called at least twice ("
1043                     + testTask.wasRun() + ")", testTask.wasRun() >= 2);
1044             t.cancel();
1045 
1046             class SlowThenFastTask extends TimerTask {
1047                 int wasRun = 0;
1048 
1049                 long startedAt;
1050 
1051                 long lastDelta;
1052 
1053                 public void run() {
1054                     if (wasRun == 0)
1055                         startedAt = System.currentTimeMillis();
1056                     lastDelta = System.currentTimeMillis()
1057                             - (startedAt + (100 * wasRun));
1058                     wasRun++;
1059                     if (wasRun == 2) {
1060                         try {
1061                             Thread.sleep(200);
1062                         } catch (InterruptedException e) {
1063                             throw new RuntimeException(e);
1064                         }
1065                     }
1066                 }
1067 
1068                 public long lastDelta() {
1069                     return lastDelta;
1070                 }
1071 
1072                 public int wasRun() {
1073                     return wasRun;
1074                 }
1075             }
1076 
1077             // Ensure multiple tasks are run
1078             t = new Timer();
1079             SlowThenFastTask slowThenFastTask = new SlowThenFastTask();
1080             d = new Date(System.currentTimeMillis() + 100);
1081 
1082             // at least 9 times even when asleep
1083             t.scheduleAtFixedRate(slowThenFastTask, d, 100);
1084             Thread.sleep(1000);
1085             long lastDelta = slowThenFastTask.lastDelta();
1086             assertTrue("Fixed Rate Schedule should catch up, but is off by "
1087                     + lastDelta + " ms", lastDelta < 300);
1088             t.cancel();
1089         } finally {
1090             if (t != null)
1091                 t.cancel();
1092         }
1093     }
1094 
1095     /**
1096      * We used to swallow RuntimeExceptions thrown by tasks. Instead, we need to
1097      * let those exceptions bubble up, where they will both notify the thread's
1098      * uncaught exception handler and terminate the timer's thread.
1099      */
1100     @Test
testThrowingTaskKillsTimerThread()1101     public void testThrowingTaskKillsTimerThread() throws Exception {
1102         final AtomicReference<Thread> threadRef = new AtomicReference<Thread>();
1103         new Timer().schedule(new TimerTask() {
1104             @Override
1105             public void run() {
1106                 Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
1107                     @Override public void uncaughtException(Thread thread, Throwable ex) {}
1108                 });
1109                 threadRef.set(Thread.currentThread());
1110                 throw new RuntimeException("task failure!");
1111             }
1112         }, 1);
1113 
1114         Thread.sleep(400);
1115         Thread timerThread = threadRef.get();
1116 
1117         // Check if the timer thread is still alive every 10ms for 2 seconds
1118         for (int i = 0; i < 200; i++) {
1119             if (!timerThread.isAlive()) {
1120                 break;
1121             }
1122             Thread.sleep(10);
1123         }
1124         assertFalse(timerThread.isAlive());
1125     }
1126 
1127     private class CheckIfExecutedOnTime extends TimerTask {
1128         private static final int TOLERANCE_TIME = 300;
1129         private final AtomicBoolean executedOnTime;
1130 
1131         static final int SLEEPING_TIME = 10 * TOLERANCE_TIME;
1132 
CheckIfExecutedOnTime(AtomicBoolean executedOnTime)1133         private CheckIfExecutedOnTime(AtomicBoolean executedOnTime) {
1134             this.executedOnTime = executedOnTime;
1135         }
1136 
1137         @Override
run()1138         public void run() {
1139             // We'll schedule one after the other to execute immediately, the first one with
1140             // {@code executedOnTime == null}. Ensure that the second
1141             // is delayed by at most the time spent by the first one, plus some tolerance.
1142             if (executedOnTime != null &&
1143                     System.currentTimeMillis()
1144                             <= scheduledExecutionTime() + SLEEPING_TIME + TOLERANCE_TIME) {
1145                 executedOnTime.set(true);
1146             } else {
1147                 try {
1148                     Thread.sleep(SLEEPING_TIME);
1149                 } catch (InterruptedException e) {
1150                     throw new IllegalStateException(e);
1151                 }
1152             }
1153         }
1154     };
1155 
1156     @Test
testOverdueTaskExecutesImmediately()1157     public void testOverdueTaskExecutesImmediately() throws Exception {
1158         Timer t = new Timer();
1159         Date date = new Date(System.currentTimeMillis());
1160         t.schedule(new CheckIfExecutedOnTime(null), date);
1161         AtomicBoolean actuallyExecutedOnTime = new AtomicBoolean();
1162         // Scheduled to execute right now but won't do as the other task is sleeping. Check that
1163         // this one executes as soon as the other one finishes.
1164         t.schedule(new CheckIfExecutedOnTime(actuallyExecutedOnTime), date);
1165         // Only the first one sleeps, this will be the two tasks plenty of time to finish.
1166         Thread.sleep(2 * CheckIfExecutedOnTime.SLEEPING_TIME);
1167         t.cancel();
1168         assertTrue(actuallyExecutedOnTime.get());
1169     }
1170 
1171     @Test
testCanBeCancelledEvenIfTaskKeepsItPermanentlyBusy()1172     public void testCanBeCancelledEvenIfTaskKeepsItPermanentlyBusy() throws Exception {
1173         final int timeSleeping = 200;
1174         Timer t = new Timer();
1175         final AtomicLong counter = new AtomicLong();
1176         TimerTask task = new TimerTask() {
1177             @Override
1178             public void run() {
1179                 try {
1180                     counter.incrementAndGet();
1181                     Thread.sleep(timeSleeping);
1182                 } catch (InterruptedException e) {
1183                     throw new IllegalStateException(e);
1184                 }
1185             }
1186         };
1187         // Keep the thread busy by scheduling execution twice as fast than the task can execute.
1188         t.scheduleAtFixedRate(task, 1 /* delay */, timeSleeping / 2 /* rate */);
1189         Thread.sleep(timeSleeping * 8);
1190         // Check the task was actually running.
1191         assertTrue(counter.get() > 0);
1192         t.cancel();
1193         // Allow some time to finish.
1194         Thread.sleep(2 * timeSleeping);
1195         try {
1196             t.schedule(
1197                     new TimerTask() {
1198                         @Override
1199                         public void run() {
1200 
1201                         }
1202                     },
1203                     1 /* delay */);
1204             fail("timer should be cancelled, and not accept new schedulings");
1205         } catch (IllegalStateException expected) {
1206             // Expected.
1207         }
1208     }
1209 
1210     @Test
testTaskNotCancelledWhenTimerCancelled()1211     public void testTaskNotCancelledWhenTimerCancelled() throws Exception {
1212         final int timeSleeping = 200;
1213         Timer t = new Timer();
1214         final AtomicLong counter = new AtomicLong();
1215         TimerTask task = new TimerTask() {
1216             @Override
1217             public void run() {
1218                 try {
1219                     counter.incrementAndGet();
1220                     Thread.sleep(timeSleeping);
1221                 } catch (InterruptedException e) {
1222                     throw new IllegalStateException(e);
1223                 }
1224             }
1225         };
1226         t.scheduleAtFixedRate(task, 1 /* delay */, 100 /* rate */);
1227         Thread.sleep(1000);
1228         t.cancel();
1229         // Returns true as the task wasn't cancelled before.
1230         assertTrue(task.cancel());
1231     }
1232 
1233     @Test
testTaskNotCancelledWhenTimerCancelledAndPurged()1234     public void testTaskNotCancelledWhenTimerCancelledAndPurged() throws Exception {
1235         final int timeSleeping = 200;
1236         Timer t = new Timer();
1237         final AtomicLong counter = new AtomicLong();
1238         TimerTask task = new TimerTask() {
1239             @Override
1240             public void run() {
1241                 try {
1242                     counter.incrementAndGet();
1243                     Thread.sleep(timeSleeping);
1244                 } catch (InterruptedException e) {
1245                     throw new IllegalStateException(e);
1246                 }
1247             }
1248         };
1249         t.scheduleAtFixedRate(task, 1 /* delay */, 100 /* rate */);
1250         Thread.sleep(1000);
1251         t.cancel();
1252         t.purge();
1253         // Returns true as the task wasn't cancelled before.
1254         assertTrue(task.cancel());
1255     }
1256 
1257     private static class IncrementCounterTaskAndPossiblyThrowAfter extends TimerTask {
1258 
1259         private final AtomicLong counter;
1260         private final int incrementAmount;
1261         private final boolean willThrow;
1262 
1263 
IncrementCounterTaskAndPossiblyThrowAfter( AtomicLong counter, int incrementAmount, boolean willThrow)1264         IncrementCounterTaskAndPossiblyThrowAfter(
1265                 AtomicLong counter, int incrementAmount, boolean willThrow) {
1266             this.counter = counter;
1267             this.incrementAmount = incrementAmount;
1268             this.willThrow = willThrow;
1269         }
1270 
1271         @Override
run()1272         public void run() {
1273             counter.addAndGet(incrementAmount);
1274             if (willThrow) {
1275                 throw new IllegalStateException("TimerTask runtime exception from run()");
1276             }
1277         }
1278     }
1279 
1280     private static class SwallowUncaughtExceptionHandler implements UncaughtExceptionHandler {
1281         CountDownLatch latch = new CountDownLatch(1);
1282         @Override
uncaughtException(Thread thread, Throwable ex)1283         public void uncaughtException(Thread thread, Throwable ex) {
1284             latch.countDown();
1285         }
1286 
waitForException(long millis)1287         void waitForException(long millis) throws InterruptedException {
1288             if(!latch.await(millis, TimeUnit.MILLISECONDS)) {
1289                 throw new AssertionError("Expected exception thrown from timer thread");
1290             }
1291         }
1292     }
1293 
1294     @Test
testTimerCancelledAfterException()1295     public void testTimerCancelledAfterException() throws Exception {
1296         UncaughtExceptionHandler excHandler = Thread.getDefaultUncaughtExceptionHandler();
1297         // Install an uncaught exception handler because we are
1298         // deliberately causing the timer thread to die in this test (which will cause CTS tests
1299         // to fail).
1300         SwallowUncaughtExceptionHandler swallowUncaughtExceptionHandler =
1301                 new SwallowUncaughtExceptionHandler();
1302         Thread.setDefaultUncaughtExceptionHandler(swallowUncaughtExceptionHandler);
1303         try {
1304             Timer t = new Timer();
1305             final AtomicLong counter = new AtomicLong();
1306 
1307             // Schedule tasks to run:
1308             // A) {In 1 millis} Increment a counter by 1 and throw an exception
1309             // B) {In 100 millis} Increment a counter by 1000 (but it's not intended to be executed
1310             //        because of the previous exception).
1311             // We want A and B to be scheduled before A runs.
1312             // We add them in reverse order.
1313             // We have ~99 millis after scheduling B to schedule A. If A ran before we scheduled B
1314             // we would get an exception when we came to schedule B.
1315             TimerTask taskThatDoesntThrow = new IncrementCounterTaskAndPossiblyThrowAfter(
1316                     counter,
1317                     1000,  /* incrementAmount */
1318                     false /* willThrow */);
1319             TimerTask taskThatThrows = new IncrementCounterTaskAndPossiblyThrowAfter(
1320                     counter,
1321                     1,    /* incrementAmount */
1322                     true  /* willThrow */);
1323             t.schedule(taskThatDoesntThrow, 100 /* delay */);
1324             t.scheduleAtFixedRate(taskThatThrows, 1 /* delay */, 100 /* period */);
1325 
1326             swallowUncaughtExceptionHandler.waitForException(1000);
1327             // Check the counter wasn't increased more than once (ie, the exception killed the
1328             // execution thread).
1329             assertEquals("Counter should be 1, and is: " + counter.get(), 1, counter.get());
1330 
1331             assertTrue("The timer should not cancel the tasks", taskThatDoesntThrow.cancel());
1332             assertTrue("The timer should not cancel the tasks", taskThatThrows.cancel());
1333 
1334             TimerTask otherTask = new TimerTask() {
1335                 @Override
1336                 public void run() {
1337                     counter.incrementAndGet();
1338                 }
1339             };
1340 
1341             try {
1342                 t.schedule(otherTask, 1);
1343                 fail("Timer should be cancelled and no new tasks should be allowed");
1344             } catch (Exception expected) {
1345                 // Expected.
1346             }
1347         } finally {
1348             Thread.setDefaultUncaughtExceptionHandler(excHandler);
1349         }
1350     }
1351 
1352     @Test
testTimerCancelledAfterExceptionAndTasksNotCancelledAfterPurge()1353     public void testTimerCancelledAfterExceptionAndTasksNotCancelledAfterPurge() throws Exception {
1354         UncaughtExceptionHandler excHandler = Thread.getDefaultUncaughtExceptionHandler();
1355         // Install an uncaught exception handler because we are
1356         // deliberately causing the timer thread to die in this test (which will cause CTS tests
1357         // to fail).
1358         SwallowUncaughtExceptionHandler swallowUncaughtExceptionHandler =
1359                 new SwallowUncaughtExceptionHandler();
1360         Thread.setDefaultUncaughtExceptionHandler(swallowUncaughtExceptionHandler);
1361         try {
1362             Timer t = new Timer();
1363             final AtomicLong counter = new AtomicLong();
1364 
1365             // Schedule tasks to run:
1366             // A) {In 1 millis} Increment a counter by 1 and throw an exception
1367             // B) {In 100 millis} Increment a counter by 1000 (but it's not intended to be executed
1368             //        because of the previous exception).
1369             // We want A and B to be scheduled before A runs.
1370             // We add them in reverse order.
1371             // We have ~99 millis after scheduling B to schedule A. If A ran before we scheduled B
1372             // we would get an exception when we came to schedule B.
1373 
1374             TimerTask taskThatDoesntThrow = new IncrementCounterTaskAndPossiblyThrowAfter(
1375                     counter,
1376                     1000, /* incrementAmount */
1377                     false /* willThrow */);
1378             TimerTask taskThatThrows = new IncrementCounterTaskAndPossiblyThrowAfter(
1379                     counter,
1380                     1,    /* incrementAmount */
1381                     true  /* willThrow */);
1382             t.schedule(taskThatDoesntThrow, 100 /* delay */);
1383             t.scheduleAtFixedRate(taskThatThrows, 1 /* delay */, 100 /* period */);
1384             swallowUncaughtExceptionHandler.waitForException(1000);
1385             // Check the counter wasn't increased more than once (ie, the exception killed the
1386             // execution thread).
1387             assertEquals("Counter should be 1, and is: " + counter.get(), 1, counter.get());
1388             t.purge();
1389             assertTrue("The timer should not cancel the tasks", taskThatDoesntThrow.cancel());
1390             assertTrue("The timer should not cancel the tasks", taskThatThrows.cancel());
1391 
1392             TimerTask otherTask = new TimerTask() {
1393                 @Override
1394                 public void run() {
1395                     counter.incrementAndGet();
1396                 }
1397             };
1398 
1399             try {
1400                 t.schedule(otherTask, 1);
1401                 fail("Timer should be cancelled and no new tasks should be allowed");
1402             } catch (Exception expected) {
1403                 // Expected.
1404             }
1405         } finally {
1406             Thread.setDefaultUncaughtExceptionHandler(excHandler);
1407         }
1408     }
1409 
1410     @Test
testTimerCancelledTasksRemovedFromQueue()1411     public void testTimerCancelledTasksRemovedFromQueue() throws Exception {
1412         Timer t = new Timer();
1413         TimerTask task1 = new TimerTask() {
1414             @Override
1415             public void run() {
1416             }
1417         };
1418         t.scheduleAtFixedRate(task1, 1 /* delay */, 10 /* period */);
1419 
1420         task1.cancel();
1421         // As the rate is 10, the timer will try to schedule it before the purge and remove it.
1422         Thread.sleep(500);
1423         assertEquals(0, t.purge());
1424     }
1425 
1426     @Before
setUp()1427     public void setUp() {
1428         timerCounter = 0;
1429     }
1430 
1431     @After
tearDown()1432     public void tearDown() {
1433     }
1434 }
1435