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