ThreadGroupTest.java revision c423b4096a09b1c1eae05b8ef37e7e3c428e0b92
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
18package org.apache.harmony.luni.tests.java.lang;
19
20import dalvik.annotation.AndroidOnly;
21import dalvik.annotation.BrokenTest;
22import dalvik.annotation.TestLevel;
23import dalvik.annotation.TestTargetNew;
24import dalvik.annotation.TestTargetClass;
25
26import java.security.Permission;
27import java.util.Vector;
28
29@TestTargetClass(ThreadGroup.class)
30public class ThreadGroupTest extends junit.framework.TestCase implements Thread.UncaughtExceptionHandler {
31
32    class MyThread extends Thread {
33        public volatile int heartBeat = 0;
34
35        public MyThread(ThreadGroup group, String name)
36                throws SecurityException, IllegalThreadStateException {
37            super(group, name);
38        }
39
40        @Override
41        public void run() {
42            while (true) {
43                heartBeat++;
44                try {
45                    Thread.sleep(50);
46                } catch (InterruptedException e) {
47                    break;
48                }
49            }
50        }
51
52        public boolean isActivelyRunning() {
53            long MAX_WAIT = 100;
54            return isActivelyRunning(MAX_WAIT);
55        }
56
57        public boolean isActivelyRunning(long maxWait) {
58            int beat = heartBeat;
59            long start = System.currentTimeMillis();
60            do {
61                Thread.yield();
62                int beat2 = heartBeat;
63                if (beat != beat2) {
64                    return true;
65                }
66            } while (System.currentTimeMillis() - start < maxWait);
67            return false;
68        }
69
70    }
71
72    private ThreadGroup rootThreadGroup = null;
73
74    private ThreadGroup initialThreadGroup = null;
75
76    /**
77     * @tests java.lang.ThreadGroup#ThreadGroup(java.lang.String)
78     */
79    @TestTargetNew(
80        level = TestLevel.COMPLETE,
81        notes = "",
82        method = "ThreadGroup",
83        args = {java.lang.String.class}
84    )
85    public void test_ConstructorLjava_lang_String() {
86        // Test for method java.lang.ThreadGroup(java.lang.String)
87
88        // Unfortunately we have to use other APIs as well as we test the
89        // constructor
90
91        ThreadGroup newGroup = null;
92        ThreadGroup initial = getInitialThreadGroup();
93        final String name = "Test name";
94        newGroup = new ThreadGroup(name);
95        assertTrue(
96                "Has to be possible to create a subgroup of current group using simple constructor",
97                newGroup.getParent() == initial);
98        assertTrue("Name has to be correct", newGroup.getName().equals(name));
99
100        // cleanup
101        newGroup.destroy();
102
103        newGroup = new ThreadGroup("");
104        assertEquals("", newGroup.getName());
105
106        newGroup = new ThreadGroup(null);
107        assertNull(newGroup.getName());
108
109        SecurityManager oldSm = System.getSecurityManager();
110        System.setSecurityManager(sm);
111        try {
112            new ThreadGroup(name);
113            fail("Should throw SecurityException");
114        } catch (SecurityException e) {
115            // expected
116        } finally {
117           System.setSecurityManager(oldSm);
118        }
119    }
120
121    /**
122     * @tests java.lang.ThreadGroup#ThreadGroup(java.lang.ThreadGroup,
123     *        java.lang.String)
124     */
125    @TestTargetNew(
126        level = TestLevel.COMPLETE,
127        notes = "",
128        method = "ThreadGroup",
129        args = {java.lang.ThreadGroup.class, java.lang.String.class}
130    )
131    public void test_ConstructorLjava_lang_ThreadGroupLjava_lang_String() {
132        // Test for method java.lang.ThreadGroup(java.lang.ThreadGroup,
133        // java.lang.String)
134
135        // Unfortunately we have to use other APIs as well as we test the
136        // constructor
137
138        ThreadGroup newGroup = null;
139
140        try {
141            newGroup = new ThreadGroup(null, null);
142        } catch (NullPointerException e) {
143        }
144        assertNull("Can't create a ThreadGroup with a null parent",
145                newGroup);
146
147        newGroup = new ThreadGroup(getInitialThreadGroup(), null);
148        assertTrue("Has to be possible to create a subgroup of current group",
149                newGroup.getParent() == Thread.currentThread().getThreadGroup());
150
151        // Lets start all over
152        newGroup.destroy();
153
154        newGroup = new ThreadGroup(getRootThreadGroup(), "a name here");
155        assertTrue("Has to be possible to create a subgroup of root group",
156                newGroup.getParent() == getRootThreadGroup());
157
158        // Lets start all over
159        newGroup.destroy();
160
161        try {
162            newGroup = new ThreadGroup(newGroup, "a name here");
163        } catch (IllegalThreadStateException e) {
164            newGroup = null;
165        }
166
167        assertNull("Can't create a subgroup of a destroyed group",
168                newGroup);
169
170        try {
171            new ThreadGroup(null, "name");
172            fail("NullPointerException is not thrown.");
173        } catch(NullPointerException npe) {
174            //expected
175        }
176
177        try {
178            new ThreadGroup(newGroup, null);
179            fail("NullPointerException is not thrown.");
180        } catch(NullPointerException npe) {
181            //expected
182        }
183
184        SecurityManager oldSm = System.getSecurityManager();
185        System.setSecurityManager(sm);
186        try {
187            new ThreadGroup(getRootThreadGroup(), "a name here");
188            fail("SecurityException was not thrown.");
189        } catch (SecurityException e) {
190            // expected
191        } finally {
192           System.setSecurityManager(oldSm);
193        }
194    }
195
196    /**
197     * @tests java.lang.ThreadGroup#activeCount()
198     */
199    @TestTargetNew(
200        level = TestLevel.COMPLETE,
201        notes = "",
202        method = "activeCount",
203        args = {}
204    )
205    public void test_activeCount() {
206        // Test for method int java.lang.ThreadGroup.activeCount()
207        ThreadGroup tg = new ThreadGroup("activeCount");
208        Thread t1 = new Thread(tg, new Runnable() {
209            public void run() {
210                try {
211                    Thread.sleep(5000);
212                } catch (InterruptedException e) {
213                }
214            }
215        });
216        int beforeCount = tg.activeCount();
217        t1.start();
218        int afterCount = tg.activeCount();
219        assertTrue("count of active threads should be increased",
220                (afterCount - beforeCount) == 1);
221        t1.interrupt();
222        try {
223            t1.join();
224        } catch (InterruptedException e) {
225        }
226        // cleanup
227        tg.destroy();
228    }
229
230    /**
231     * @tests java.lang.ThreadGroup#activeGroupCount()
232     */
233    @TestTargetNew(
234        level = TestLevel.COMPLETE,
235        notes = "",
236        method = "activeGroupCount",
237        args = {}
238    )
239    public void test_activeGroupCount() {
240
241        ThreadGroup tg = new ThreadGroup("group count");
242        assertEquals("Incorrect number of groups",
243                0, tg.activeGroupCount());
244        Thread t1 = new Thread(tg, new Runnable() {
245            public void run() {
246
247            }
248        });
249        assertEquals("Incorrect number of groups",
250                0, tg.activeGroupCount());
251        t1.start();
252        assertEquals("Incorrect number of groups",
253                0, tg.activeGroupCount());
254        new ThreadGroup(tg, "test group 1");
255        assertEquals("Incorrect number of groups",
256                1, tg.activeGroupCount());
257        new ThreadGroup(tg, "test group 2");
258        assertEquals("Incorrect number of groups",
259                2, tg.activeGroupCount());
260    }
261
262    /**
263     * @tests java.lang.ThreadGroup#allowThreadSuspension(boolean)
264     */
265    @TestTargetNew(
266        level = TestLevel.COMPLETE,
267        notes = "",
268        method = "allowThreadSuspension",
269        args = {boolean.class}
270    )
271    @SuppressWarnings("deprecation")
272    public void test_allowThreadSuspensionZ() {
273        ThreadGroup tg = new ThreadGroup("thread suspension");
274        assertTrue("Thread suspention can not be changed",
275                tg.allowThreadSuspension(false));
276        assertTrue("Thread suspention can not be changed",
277                tg.allowThreadSuspension(true));
278    }
279
280    /**
281     * @tests java.lang.ThreadGroup#checkAccess()
282     */
283    @TestTargetNew(
284        level = TestLevel.COMPLETE,
285        notes = "",
286        method = "checkAccess",
287        args = {}
288    )
289    public void test_checkAccess() {
290        // Test for method void java.lang.ThreadGroup.checkAccess()
291
292        final ThreadGroup originalCurrent = getInitialThreadGroup();
293        ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
294
295        SecurityManager currentManager = System.getSecurityManager();
296        boolean passed = true;
297
298        try {
299            if (currentManager != null) {
300                testRoot.checkAccess();
301            }
302        } catch (SecurityException se) {
303            passed = false;
304        }
305
306        assertTrue("CheckAccess is no-op with no SecurityManager", passed);
307
308        testRoot.destroy();
309
310        SecurityManager oldSm = System.getSecurityManager();
311        System.setSecurityManager(sm);
312        try {
313            testRoot.checkAccess();
314            fail("Should throw SecurityException");
315        } catch (SecurityException e) {
316            // expected
317        } finally {
318           System.setSecurityManager(oldSm);
319        }
320    }
321
322    /*
323     * Checks whether the current Thread is in the given list.
324     */
325    private boolean inListOfThreads(Thread[] threads) {
326        for (int i = 0; i < threads.length; i++) {
327            if (Thread.currentThread() == threads[i]) {
328                return true;
329            }
330        }
331
332        return false;
333    }
334
335    @TestTargetNew(
336        level = TestLevel.COMPLETE,
337        notes = "",
338        method = "enumerate",
339        args = {java.lang.Thread[].class}
340    )
341    public void test_enumerateLThreadArray() {
342        int numThreads = initialThreadGroup.activeCount();
343        Thread[] listOfThreads = new Thread[numThreads];
344
345        int countThread = initialThreadGroup.enumerate(listOfThreads);
346        assertEquals(numThreads, countThread);
347        assertTrue("Current thread must be in enumeration of threads",
348                inListOfThreads(listOfThreads));
349
350        SecurityManager oldSm = System.getSecurityManager();
351        System.setSecurityManager(sm);
352        try {
353            initialThreadGroup.enumerate(listOfThreads);
354            fail("Should throw SecurityException");
355        } catch (SecurityException e) {
356            // expected
357        } finally {
358           System.setSecurityManager(oldSm);
359        }
360    }
361
362    @TestTargetNew(
363        level = TestLevel.COMPLETE,
364        notes = "",
365        method = "enumerate",
366        args = {java.lang.Thread[].class, boolean.class}
367    )
368    public void test_enumerateLThreadArrayLZ() {
369        int numThreads = initialThreadGroup.activeCount();
370        Thread[] listOfThreads = new Thread[numThreads];
371
372        int countThread = initialThreadGroup.enumerate(listOfThreads, false);
373        assertEquals(numThreads, countThread);
374
375        countThread = initialThreadGroup.enumerate(listOfThreads, true);
376        assertEquals(numThreads, countThread);
377        assertTrue("Current thread must be in enumeration of threads",
378                inListOfThreads(listOfThreads));
379
380        ThreadGroup subGroup = new ThreadGroup(initialThreadGroup, "Test Group 1");
381        int subThreadsCount = 3;
382        Vector<MyThread> subThreads = populateGroupsWithThreads(subGroup,
383                subThreadsCount);
384
385        countThread = initialThreadGroup.enumerate(listOfThreads, true);
386        assertEquals(numThreads, countThread);
387        assertTrue("Current thread must be in enumeration of threads",
388                inListOfThreads(listOfThreads));
389
390        for(MyThread thr:subThreads) {
391            thr.start();
392        }
393        // lets give them some time to start
394        try {
395            Thread.sleep(500);
396        } catch (InterruptedException ie) {
397            fail("Should not be interrupted");
398        }
399
400        int numThreads2 = initialThreadGroup.activeCount();
401        listOfThreads = new Thread[numThreads2];
402
403        assertEquals(numThreads + subThreadsCount, numThreads2);
404
405        countThread = initialThreadGroup.enumerate(listOfThreads, true);
406        assertEquals(numThreads2, countThread);
407        assertTrue("Current thread must be in enumeration of threads",
408                inListOfThreads(listOfThreads));
409
410        for(MyThread thr:subThreads) {
411            thr.interrupt();
412        }
413        // lets give them some time to die
414        try {
415            Thread.sleep(500);
416        } catch (InterruptedException ie) {
417            fail("Should not be interrupted");
418        }
419
420        int numThreads3 = initialThreadGroup.activeCount();
421        listOfThreads = new Thread[numThreads3];
422
423        assertEquals(numThreads, numThreads3);
424
425        countThread = initialThreadGroup.enumerate(listOfThreads, false);
426        assertEquals(numThreads3, countThread);
427        assertTrue("Current thread must be in enumeration of threads",
428                inListOfThreads(listOfThreads));
429
430        SecurityManager oldSm = System.getSecurityManager();
431        System.setSecurityManager(sm);
432        try {
433            initialThreadGroup.enumerate(listOfThreads, true);
434            fail("Should throw SecurityException");
435        } catch (SecurityException e) {
436            // expected
437        } finally {
438           System.setSecurityManager(oldSm);
439        }
440    }
441
442    @TestTargetNew(
443        level = TestLevel.COMPLETE,
444        notes = "",
445        method = "enumerate",
446        args = {java.lang.ThreadGroup[].class}
447    )
448    @BrokenTest("Fails in CTS environment, but passes in CoreTestRunner")
449    public void test_enumerateLThreadGroupArray() {
450        int numGroupThreads = initialThreadGroup.activeGroupCount();
451        ThreadGroup[] listOfGroups = new ThreadGroup[numGroupThreads];
452
453        int countGroupThread = initialThreadGroup.enumerate(listOfGroups);
454        assertEquals(numGroupThreads, countGroupThread);
455
456        ThreadGroup[] listOfGroups1 = new ThreadGroup[numGroupThreads + 1];
457        countGroupThread = initialThreadGroup.enumerate(listOfGroups1);
458        assertEquals(numGroupThreads, countGroupThread);
459        assertNull(listOfGroups1[listOfGroups1.length - 1]);
460
461        ThreadGroup[] listOfGroups2 = new ThreadGroup[numGroupThreads - 1];
462        countGroupThread = initialThreadGroup.enumerate(listOfGroups2);
463        assertEquals(numGroupThreads - 1, countGroupThread);
464
465        ThreadGroup thrGroup1 = new ThreadGroup("Test Group 1");
466        countGroupThread = thrGroup1.enumerate(listOfGroups);
467        assertEquals(0, countGroupThread);
468
469        SecurityManager oldSm = System.getSecurityManager();
470        System.setSecurityManager(sm);
471        try {
472            initialThreadGroup.enumerate(listOfGroups);
473            fail("Should throw SecurityException");
474        } catch (SecurityException e) {
475            // expected
476        } finally {
477           System.setSecurityManager(oldSm);
478        }
479     }
480
481    @TestTargetNew(
482        level = TestLevel.COMPLETE,
483        notes = "",
484        method = "enumerate",
485        args = {java.lang.ThreadGroup[].class, boolean.class}
486    )
487    public void test_enumerateLThreadGroupArrayLZ() {
488        ThreadGroup thrGroup = new ThreadGroup("Test Group 1");
489        Vector<MyThread> subThreads = populateGroupsWithThreads(thrGroup, 3);
490        int numGroupThreads = thrGroup.activeGroupCount();
491        ThreadGroup[] listOfGroups = new ThreadGroup[numGroupThreads];
492
493        assertEquals(0, thrGroup.enumerate(listOfGroups, true));
494        assertEquals(0, thrGroup.enumerate(listOfGroups, false));
495
496        for(MyThread thr:subThreads) {
497            thr.start();
498        }
499
500        numGroupThreads = thrGroup.activeGroupCount();
501        listOfGroups = new ThreadGroup[numGroupThreads];
502
503        assertEquals(0, thrGroup.enumerate(listOfGroups, true));
504        assertEquals(0, thrGroup.enumerate(listOfGroups, false));
505
506        ThreadGroup subGroup1 = new ThreadGroup(thrGroup, "Test Group 2");
507        Vector<MyThread> subThreads1 = populateGroupsWithThreads(subGroup1, 3);
508        numGroupThreads = thrGroup.activeGroupCount();
509        listOfGroups = new ThreadGroup[numGroupThreads];
510
511        assertEquals(1, thrGroup.enumerate(listOfGroups, true));
512        assertEquals(1, thrGroup.enumerate(listOfGroups, false));
513
514        for(MyThread thr:subThreads1) {
515            thr.start();
516        }
517        numGroupThreads = thrGroup.activeGroupCount();
518        listOfGroups = new ThreadGroup[numGroupThreads];
519
520        assertEquals(1, thrGroup.enumerate(listOfGroups, true));
521        assertEquals(1, thrGroup.enumerate(listOfGroups, false));
522
523        for(MyThread thr:subThreads) {
524            thr.interrupt();
525         }
526
527        ThreadGroup subGroup2 = new ThreadGroup(subGroup1, "Test Group 3");
528        Vector<MyThread> subThreads2 = populateGroupsWithThreads(subGroup2, 3);
529        numGroupThreads = thrGroup.activeGroupCount();
530        listOfGroups = new ThreadGroup[numGroupThreads];
531
532        assertEquals(2, thrGroup.enumerate(listOfGroups, true));
533        assertEquals(1, thrGroup.enumerate(listOfGroups, false));
534
535        SecurityManager oldSm = System.getSecurityManager();
536        System.setSecurityManager(sm);
537        try {
538            thrGroup.enumerate(listOfGroups, true);
539            fail("Should throw SecurityException");
540        } catch (SecurityException e) {
541            // expected
542        } finally {
543           System.setSecurityManager(oldSm);
544        }
545    }
546
547    /**
548     * @tests java.lang.ThreadGroup#destroy()
549     */
550    @TestTargetNew(
551        level = TestLevel.COMPLETE,
552        notes = "",
553        method = "destroy",
554        args = {}
555    )
556    public void test_destroy() {
557        // Test for method void java.lang.ThreadGroup.destroy()
558
559        final ThreadGroup originalCurrent = getInitialThreadGroup();
560        ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
561        final int DEPTH = 4;
562        final Vector<ThreadGroup> subgroups = buildRandomTreeUnder(testRoot, DEPTH);
563
564        // destroy them all
565        testRoot.destroy();
566
567        for (int i = 0; i < subgroups.size(); i++) {
568            ThreadGroup child = subgroups.elementAt(i);
569            assertEquals("Destroyed child can't have children", 0, child
570                    .activeCount());
571            boolean passed = false;
572            try {
573                child.destroy();
574            } catch (IllegalThreadStateException e) {
575                passed = true;
576            }
577
578            assertTrue("Destroyed child can't be destroyed again", passed);
579        }
580
581        testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
582        testRoot.setDaemon(true);
583
584        ThreadGroup child = new ThreadGroup(testRoot, "daemon child");
585
586        // If we destroy the last daemon's child, the daemon should get destroyed
587        // as well
588        child.destroy();
589
590        boolean passed = false;
591        try {
592            child.destroy();
593        } catch (IllegalThreadStateException e) {
594            passed = true;
595        }
596
597        assertTrue("Daemon should have been destroyed already", passed);
598
599        passed = false;
600        try {
601            testRoot.destroy();
602        } catch (IllegalThreadStateException e) {
603            passed = true;
604        }
605
606        assertTrue("Daemon parent should have been destroyed automatically",
607                passed);
608
609        assertTrue(
610                "Destroyed daemon's child should not be in daemon's list anymore",
611                !arrayIncludes(groups(testRoot), child));
612        assertTrue("Destroyed daemon should not be in parent's list anymore",
613                !arrayIncludes(groups(originalCurrent), testRoot));
614
615        testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
616        testRoot.setDaemon(true);
617        Thread noOp = new Thread(testRoot, null, "no-op thread") {
618            @Override
619            public void run() {
620            }
621        };
622        noOp.start();
623
624        // Wait for the no-op thread to run inside daemon ThreadGroup
625        try {
626            noOp.join();
627        } catch (InterruptedException ie) {
628            fail("Should not be interrupted");
629        }
630
631
632        passed = false;
633        try {
634            child.destroy();
635        } catch (IllegalThreadStateException e) {
636            passed = true;
637        }
638
639        assertTrue(
640                "Daemon group should have been destroyed already when last thread died",
641                passed);
642
643        testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
644        noOp = new Thread(testRoot, null, "no-op thread") {
645            @Override
646            public void run() {
647                try {
648                    Thread.sleep(500);
649                } catch (InterruptedException ie) {
650                    fail("Should not be interrupted");
651                }
652            }
653        };
654
655        // Has to execute the next lines in an interval < the sleep interval of
656        // the no-op thread
657        noOp.start();
658        passed = false;
659        try {
660            testRoot.destroy();
661        } catch (IllegalThreadStateException its) {
662            passed = true;
663        }
664        assertTrue("Can't destroy a ThreadGroup that has threads", passed);
665
666        // But after the thread dies, we have to be able to destroy the thread
667        // group
668        try {
669            noOp.join();
670        } catch (InterruptedException ie) {
671            fail("Should not be interrupted");
672        }
673
674        passed = true;
675        try {
676            testRoot.destroy();
677        } catch (IllegalThreadStateException its) {
678            passed = false;
679        }
680        assertTrue(
681                "Should be able to destroy a ThreadGroup that has no threads",
682                passed);
683
684        ThreadGroup tg = new ThreadGroup("ThreadGroup");
685        SecurityManager oldSm = System.getSecurityManager();
686        System.setSecurityManager(sm);
687        try {
688            originalCurrent.destroy();
689            fail("Should throw SecurityException");
690        } catch (SecurityException e) {
691            // expected
692        } finally {
693           System.setSecurityManager(oldSm);
694        }
695    }
696
697    /**
698     * @tests java.lang.ThreadGroup#destroy()
699     */
700    @TestTargetNew(
701        level = TestLevel.PARTIAL,
702        notes = "Verifies IllegalThreadStateException.",
703        method = "destroy",
704        args = {}
705    )
706    public void test_destroy_subtest0() {
707        ThreadGroup group1 = new ThreadGroup("test_destroy_subtest0");
708        group1.destroy();
709        try {
710            new Thread(group1, "test_destroy_subtest0");
711            fail("should throw IllegalThreadStateException");
712        } catch (IllegalThreadStateException e) {
713        }
714    }
715
716    /**
717     * @tests java.lang.ThreadGroup#getMaxPriority()
718     */
719    @TestTargetNew(
720        level = TestLevel.COMPLETE,
721        notes = "",
722        method = "getMaxPriority",
723        args = {}
724    )
725    public void test_getMaxPriority() {
726        // Test for method int java.lang.ThreadGroup.getMaxPriority()
727        final ThreadGroup originalCurrent = getInitialThreadGroup();
728        ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
729
730        boolean passed = true;
731        try {
732            testRoot.setMaxPriority(Thread.MIN_PRIORITY);
733        } catch (IllegalArgumentException iae) {
734            passed = false;
735        }
736        assertTrue("Should be able to set priority", passed);
737
738        assertTrue("New value should be the same as we set", testRoot
739                .getMaxPriority() == Thread.MIN_PRIORITY);
740
741        testRoot.destroy();
742
743    }
744
745    /**
746     * @tests java.lang.ThreadGroup#getName()
747     */
748    @TestTargetNew(
749        level = TestLevel.COMPLETE,
750        notes = "",
751        method = "getName",
752        args = {}
753    )
754    public void test_getName() {
755        // Test for method java.lang.String java.lang.ThreadGroup.getName()
756        final ThreadGroup originalCurrent = getInitialThreadGroup();
757        final String name = "Test group";
758        final ThreadGroup testRoot = new ThreadGroup(originalCurrent, name);
759
760        assertTrue("Setting a name&getting does not work", testRoot.getName()
761                .equals(name));
762
763        testRoot.destroy();
764
765    }
766
767    /**
768     * @tests java.lang.ThreadGroup#getParent()
769     */
770    @TestTargetNew(
771        level = TestLevel.COMPLETE,
772        notes = "",
773        method = "getParent",
774        args = {}
775    )
776    public void test_getParent() {
777        // Test for method java.lang.ThreadGroup
778        // java.lang.ThreadGroup.getParent()
779        final ThreadGroup originalCurrent = getInitialThreadGroup();
780        ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
781
782        assertTrue("Parent is wrong", testRoot.getParent() == originalCurrent);
783
784        // Create some groups, nested some levels.
785        final int TOTAL_DEPTH = 5;
786        ThreadGroup current = testRoot;
787        Vector<ThreadGroup> groups = new Vector<ThreadGroup>();
788        // To maintain the invariant that a thread in the Vector is parent
789        // of the next one in the collection (and child of the previous one)
790        groups.addElement(testRoot);
791
792        for (int i = 0; i < TOTAL_DEPTH; i++) {
793            current = new ThreadGroup(current, "level " + i);
794            groups.addElement(current);
795        }
796
797        // Now we walk the levels down, checking if parent is ok
798        for (int i = 1; i < groups.size(); i++) {
799            current = groups.elementAt(i);
800            ThreadGroup previous = groups.elementAt(i - 1);
801            assertTrue("Parent is wrong", current.getParent() == previous);
802        }
803
804        final ThreadGroup[] checkAccessGroup = new ThreadGroup[1];
805        class SecurityManagerImpl extends MutableSecurityManager {
806            @Override
807            public void checkAccess(ThreadGroup group) {
808                checkAccessGroup[0] = group;
809            }
810        }
811        SecurityManagerImpl sm = new SecurityManagerImpl();
812        //add permission to allow reset of security manager
813        sm.addPermission(MutableSecurityManager.SET_SECURITY_MANAGER);
814
815        ThreadGroup parent;
816        try {
817            // To see if it checks Thread creation with our SecurityManager
818            System.setSecurityManager(sm);
819            parent = testRoot.getParent();
820        } finally {
821            // restore original, no side-effects
822            System.setSecurityManager(null);
823        }
824        assertTrue("checkAccess with incorrect group",
825                checkAccessGroup[0] == parent);
826
827        testRoot.destroy();
828    }
829
830    /**
831     * @tests java.lang.ThreadGroup#interrupt()
832     */
833    private static boolean interrupted = false;
834    @TestTargetNew(
835        level = TestLevel.COMPLETE,
836        notes = "",
837        method = "interrupt",
838        args = {}
839    )
840    public void test_interrupt() {
841
842        Thread.setDefaultUncaughtExceptionHandler(this);
843        ThreadGroup tg = new ThreadGroup("interrupt");
844        Thread t1 = new Thread(tg, new Runnable() {
845            public void run() {
846                try {
847                    Thread.sleep(5000);
848                } catch (InterruptedException e) {
849                    fail("ok");
850                }
851            }
852        });
853        assertFalse("Incorrect state of thread", interrupted);
854        t1.start();
855        assertFalse("Incorrect state of thread", interrupted);
856        t1.interrupt();
857        try {
858            t1.join();
859        } catch (InterruptedException e) {
860        }
861        assertTrue("Incorrect state of thread", interrupted);
862        tg.destroy();
863
864        ThreadGroup threadGroup = new ThreadGroup("securityCheck");
865        SecurityManager oldSm = System.getSecurityManager();
866        System.setSecurityManager(sm);
867        try {
868            threadGroup.interrupt();
869            fail("Should throw SecurityException");
870        } catch (SecurityException e) {
871            // expected
872        } finally {
873           System.setSecurityManager(oldSm);
874        }
875    }
876
877    /**
878     * @tests java.lang.ThreadGroup#isDaemon()
879     */
880    @TestTargetNew(
881        level = TestLevel.COMPLETE,
882        notes = "",
883        method = "isDaemon",
884        args = {}
885    )
886    public void test_isDaemon() {
887        // Test for method boolean java.lang.ThreadGroup.isDaemon()
888        daemonTests();
889    }
890
891    /**
892     * @tests java.lang.ThreadGroup#isDestroyed()
893     */
894    @TestTargetNew(
895        level = TestLevel.COMPLETE,
896        notes = "",
897        method = "isDestroyed",
898        args = {}
899    )
900    public void test_isDestroyed() {
901        final ThreadGroup originalCurrent = getInitialThreadGroup();
902        final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
903                "Test group");
904        assertFalse("Test group is not destroyed yet",
905                testRoot.isDestroyed());
906        testRoot.destroy();
907        assertTrue("Test group already destroyed",
908                testRoot.isDestroyed());
909    }
910
911    /**
912     * @tests java.lang.ThreadGroup#list()
913     */
914    @TestTargetNew(
915        level = TestLevel.COMPLETE,
916        notes = "",
917        method = "list",
918        args = {}
919    )
920    public void test_list() {
921        // Test for method void java.lang.ThreadGroup.list()
922
923        final ThreadGroup originalCurrent = getInitialThreadGroup();
924        // wipeSideEffectThreads destroy all side effect of threads created in
925        // java.lang.Thread
926        boolean result = wipeSideEffectThreads(originalCurrent);
927        if (result == false) {
928            fail("wipe threads in test_list() not successful");
929        }
930        final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
931                "Test group");
932
933        // First save the original System.out
934        java.io.PrintStream originalOut = System.out;
935
936        try {
937            java.io.ByteArrayOutputStream contentsStream = new java.io.ByteArrayOutputStream(
938                    100);
939            java.io.PrintStream newOut = new java.io.PrintStream(contentsStream);
940
941            // We have to "redirect" System.out to test the method 'list'
942            System.setOut(newOut);
943
944            originalCurrent.list();
945
946            /*
947             * The output has to look like this
948             *
949             * java.lang.ThreadGroup[name=main,maxpri=10] Thread[main,5,main]
950             * java.lang.ThreadGroup[name=Test group,maxpri=10]
951             *
952             */
953
954            String contents = new String(contentsStream.toByteArray());
955            boolean passed = (contents.indexOf("ThreadGroup[name=main") != -1) &&
956                             (contents.indexOf("Thread[") != -1) &&
957                             (contents.indexOf("ThreadGroup[name=Test group") != -1);
958            assertTrue("'list()' does not print expected contents. "
959                    + "Result from list: "
960                    + contents, passed);
961            // Do proper cleanup
962            testRoot.destroy();
963
964        } finally {
965            // No matter what, we need to restore the original System.out
966            System.setOut(originalOut);
967        }
968
969    }
970
971    /**
972     * @tests java.lang.ThreadGroup#parentOf(java.lang.ThreadGroup)
973     */
974    @TestTargetNew(
975        level = TestLevel.COMPLETE,
976        notes = "",
977        method = "parentOf",
978        args = {java.lang.ThreadGroup.class}
979    )
980    public void test_parentOfLjava_lang_ThreadGroup() {
981        // Test for method boolean
982        // java.lang.ThreadGroup.parentOf(java.lang.ThreadGroup)
983        final ThreadGroup originalCurrent = getInitialThreadGroup();
984        final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
985                "Test group");
986        final int DEPTH = 4;
987        buildRandomTreeUnder(testRoot, DEPTH);
988
989        final ThreadGroup[] allChildren = allGroups(testRoot);
990        for (ThreadGroup element : allChildren) {
991            assertTrue("Have to be parentOf all children", testRoot
992                    .parentOf(element));
993        }
994
995        assertTrue("Have to be parentOf itself", testRoot.parentOf(testRoot));
996
997        testRoot.destroy();
998        assertTrue("Parent can't have test group as subgroup anymore",
999                !arrayIncludes(groups(testRoot.getParent()), testRoot));
1000
1001        try {
1002            System.setSecurityManager(new MutableSecurityManager(MutableSecurityManager.SET_SECURITY_MANAGER));
1003            assertTrue("Should not be parent", !testRoot
1004                    .parentOf(originalCurrent));
1005        } finally {
1006            System.setSecurityManager(null);
1007        }
1008    }
1009
1010    /**
1011     * @tests java.lang.ThreadGroup#resume()
1012     */
1013    @TestTargetNew(
1014        level = TestLevel.COMPLETE,
1015        notes = "",
1016        method = "resume",
1017        args = {}
1018    )
1019    @AndroidOnly("RI does implement this method, whereas Android does not")
1020    @SuppressWarnings("deprecation")
1021    public void test_resume() {
1022        ThreadGroup group = new ThreadGroup("Foo");
1023
1024        Thread thread = launchFiveSecondDummyThread(group);
1025
1026        try {
1027            Thread.sleep(1000);
1028        } catch (InterruptedException e) {
1029            // Ignore
1030        }
1031
1032        // No-op in Android. Must neither have an effect nor throw an exception.
1033        Thread.State state = thread.getState();
1034        group.resume();
1035        assertEquals(state, thread.getState());
1036
1037        // Security checks are made even though method is not supported.
1038        SecurityManager oldSm = System.getSecurityManager();
1039        System.setSecurityManager(new ThreadSecurityManager());
1040        try {
1041            group.resume();
1042            fail("Should throw SecurityException");
1043        } catch (SecurityException e) {
1044            // expected
1045        } finally {
1046            System.setSecurityManager(oldSm);
1047        }
1048
1049        try {
1050            thread.join();
1051        } catch (InterruptedException e) {
1052            // Ignore
1053        }
1054    }
1055
1056    /**
1057     * @tests java.lang.ThreadGroup#setDaemon(boolean)
1058     */
1059    @TestTargetNew(
1060        level = TestLevel.COMPLETE,
1061        notes = "",
1062        method = "setDaemon",
1063        args = {boolean.class}
1064    )
1065    public void test_setDaemonZ() {
1066        // Test for method void java.lang.ThreadGroup.setDaemon(boolean)
1067        daemonTests();
1068
1069        final ThreadGroup testRoot = new ThreadGroup("Test group");
1070
1071        testRoot.setDaemon(true);
1072
1073        SecurityManager oldSm = System.getSecurityManager();
1074        System.setSecurityManager(sm);
1075
1076        try {
1077            new ThreadGroup("");
1078            fail("Should throw SecurityException");
1079        } catch (SecurityException e) {
1080            // expected
1081        } finally {
1082           System.setSecurityManager(oldSm);
1083        }
1084    }
1085
1086    /**
1087     * @tests java.lang.ThreadGroup#setMaxPriority(int)
1088     */
1089    @TestTargetNew(
1090        level = TestLevel.COMPLETE,
1091        notes = "",
1092        method = "setMaxPriority",
1093        args = {int.class}
1094    )
1095    public void test_setMaxPriorityI() {
1096        // Test for method void java.lang.ThreadGroup.setMaxPriority(int)
1097        final ThreadGroup originalCurrent = getInitialThreadGroup();
1098        ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
1099
1100        boolean passed;
1101
1102        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1103
1104        int currentMax = testRoot.getMaxPriority();
1105        testRoot.setMaxPriority(Thread.MAX_PRIORITY + 1);
1106        passed = testRoot.getMaxPriority() == currentMax;
1107        assertTrue(
1108                "setMaxPriority: Any value higher than the current one is ignored. Before: "
1109                        + currentMax + " , after: " + testRoot.getMaxPriority(),
1110                passed);
1111
1112        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1113
1114        currentMax = testRoot.getMaxPriority();
1115        testRoot.setMaxPriority(Thread.MIN_PRIORITY - 1);
1116        passed = testRoot.getMaxPriority() == Thread.MIN_PRIORITY;
1117        assertTrue(
1118                "setMaxPriority: Any value smaller than MIN_PRIORITY is adjusted to MIN_PRIORITY. Before: "
1119                        + currentMax + " , after: " + testRoot.getMaxPriority(),
1120                passed);
1121
1122        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1123
1124        testRoot.destroy();
1125        testRoot = new ThreadGroup(originalCurrent, "Test group");
1126
1127        // Create some groups, nested some levels. Each level will have maxPrio
1128        // 1 unit smaller than the parent's. However, there can't be a group
1129        // with priority < Thread.MIN_PRIORITY
1130        final int TOTAL_DEPTH = testRoot.getMaxPriority() - Thread.MIN_PRIORITY
1131                - 2;
1132        ThreadGroup current = testRoot;
1133        for (int i = 0; i < TOTAL_DEPTH; i++) {
1134            current = new ThreadGroup(current, "level " + i);
1135        }
1136
1137        // Now we walk the levels down, changing the maxPrio and later verifying
1138        // that the value is indeed 1 unit smaller than the parent's maxPrio.
1139        int maxPrio, parentMaxPrio;
1140        current = testRoot;
1141
1142        // To maintain the invariant that when we are to modify a child,
1143        // its maxPriority is always 1 unit smaller than its parent's.
1144        // We have to set it for the root manually, and the loop does the rest
1145        // for all the other sub-levels
1146        current.setMaxPriority(current.getParent().getMaxPriority() - 1);
1147
1148        for (int i = 0; i < TOTAL_DEPTH; i++) {
1149            maxPrio = current.getMaxPriority();
1150            parentMaxPrio = current.getParent().getMaxPriority();
1151
1152            ThreadGroup[] children = groups(current);
1153            assertEquals("Can only have 1 subgroup", 1, children.length);
1154            current = children[0];
1155            assertTrue(
1156                    "Had to be 1 unit smaller than parent's priority in iteration="
1157                            + i + " checking->" + current,
1158                    maxPrio == parentMaxPrio - 1);
1159            current.setMaxPriority(maxPrio - 1);
1160
1161            // The next test is sort of redundant, since in next iteration it
1162            // will be the parent tGroup, so the test will be done.
1163            assertTrue("Had to be possible to change max priority", current
1164                    .getMaxPriority() == maxPrio - 1);
1165        }
1166
1167        assertTrue(
1168                "Priority of leaf child group has to be much smaller than original root group",
1169                current.getMaxPriority() == testRoot.getMaxPriority()
1170                        - TOTAL_DEPTH);
1171
1172        testRoot.destroy();
1173
1174        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1175
1176        passed = true;
1177        testRoot = new ThreadGroup(originalCurrent, "Test group");
1178        try {
1179            testRoot.setMaxPriority(Thread.MAX_PRIORITY);
1180        } catch (IllegalArgumentException iae) {
1181            passed = false;
1182        }
1183        assertTrue(
1184                "Max Priority = Thread.MAX_PRIORITY should be possible if the test is run with default system ThreadGroup as root",
1185                passed);
1186        testRoot.destroy();
1187
1188        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1189
1190        passed = true;
1191        testRoot = new ThreadGroup(originalCurrent, "Test group");
1192        System.setSecurityManager(new MutableSecurityManager(MutableSecurityManager.SET_SECURITY_MANAGER));
1193        try {
1194            try {
1195                testRoot.setMaxPriority(Thread.MIN_PRIORITY);
1196            } catch (IllegalArgumentException iae) {
1197                passed = false;
1198            }
1199        } finally {
1200            System.setSecurityManager(null);
1201        }
1202        assertTrue(
1203                "Min Priority = Thread.MIN_PRIORITY should be possible, always",
1204                passed);
1205        testRoot.destroy();
1206
1207        try {
1208            System.setSecurityManager(new MutableSecurityManager(MutableSecurityManager.SET_SECURITY_MANAGER));
1209            originalCurrent.setMaxPriority(Thread.MAX_PRIORITY);
1210        } finally {
1211            System.setSecurityManager(null);
1212        }
1213
1214        SecurityManager oldSm = System.getSecurityManager();
1215        System.setSecurityManager(sm);
1216
1217        try {
1218            testRoot.setMaxPriority(Thread.MAX_PRIORITY);
1219            fail("Should throw SecurityException");
1220        } catch (SecurityException e) {
1221            // expected
1222        } finally {
1223           System.setSecurityManager(oldSm);
1224        }
1225    }
1226
1227    /**
1228     * @tests java.lang.ThreadGroup#stop()
1229     */
1230    @TestTargetNew(
1231        level = TestLevel.COMPLETE,
1232        notes = "",
1233        method = "stop",
1234        args = {}
1235    )
1236    @AndroidOnly("RI does implement this method, whereas Android does not")
1237    @SuppressWarnings("deprecation")
1238    public void test_stop() {
1239        ThreadGroup group = new ThreadGroup("Foo");
1240
1241        Thread thread = launchFiveSecondDummyThread(group);
1242
1243        try {
1244            Thread.sleep(1000);
1245        } catch (InterruptedException e) {
1246            // Ignore
1247        }
1248
1249        // No-op in Android. Must neither have an effect nor throw an exception.
1250        Thread.State state = thread.getState();
1251        group.stop();
1252        assertEquals(state, thread.getState());
1253
1254        // Security checks are made even though method is not supported.
1255        SecurityManager oldSm = System.getSecurityManager();
1256        System.setSecurityManager(new ThreadSecurityManager());
1257        try {
1258            group.stop();
1259            fail("Should throw SecurityException");
1260        } catch (SecurityException e) {
1261            // expected
1262        } finally {
1263            System.setSecurityManager(oldSm);
1264        }
1265
1266        try {
1267            thread.join();
1268        } catch (InterruptedException e) {
1269            // Ignore
1270        }
1271    }
1272
1273    private Thread launchFiveSecondDummyThread(ThreadGroup group) {
1274        Thread thread = new Thread(group, "Bar") {
1275            public void run() {
1276                try {
1277                    Thread.sleep(5000);
1278                } catch (InterruptedException e) {
1279                    // Ignore
1280                }
1281            }
1282        };
1283
1284        thread.start();
1285
1286        return thread;
1287    }
1288
1289    private class ThreadSecurityManager extends SecurityManager {
1290        public void checkPermission(Permission perm) {
1291        }
1292
1293        public void checkAccess(Thread t) {
1294            throw new SecurityException();
1295        }
1296    };
1297
1298    /**
1299     * @tests java.lang.ThreadGroup#suspend()
1300     */
1301    @TestTargetNew(
1302        level = TestLevel.COMPLETE,
1303        notes = "",
1304        method = "suspend",
1305        args = {}
1306    )
1307    @AndroidOnly("RI does implement this method, whereas Android does not")
1308    @SuppressWarnings("deprecation")
1309    public void test_suspend() {
1310        ThreadGroup group = new ThreadGroup("Foo");
1311
1312        Thread thread = launchFiveSecondDummyThread(group);
1313
1314        try {
1315            Thread.sleep(1000);
1316        } catch (InterruptedException e) {
1317            // Ignore
1318        }
1319
1320        // No-op in Android. Must neither have an effect nor throw an exception.
1321        Thread.State state = thread.getState();
1322        group.suspend();
1323        assertEquals(state, thread.getState());
1324
1325        // Security checks are made even though method is not supported.
1326        SecurityManager oldSm = System.getSecurityManager();
1327        System.setSecurityManager(new ThreadSecurityManager());
1328        try {
1329            group.suspend();
1330            fail("Should throw SecurityException");
1331        } catch (SecurityException e) {
1332            // expected
1333        } finally {
1334            System.setSecurityManager(oldSm);
1335        }
1336
1337        try {
1338            thread.join();
1339        } catch (InterruptedException e) {
1340            // Ignore
1341        }
1342    }
1343
1344    /**
1345     * @tests java.lang.ThreadGroup#toString()
1346     */
1347    @TestTargetNew(
1348        level = TestLevel.COMPLETE,
1349        notes = "",
1350        method = "toString",
1351        args = {}
1352    )
1353    public void test_toString() {
1354        // Test for method java.lang.String java.lang.ThreadGroup.toString()
1355        final ThreadGroup originalCurrent = getInitialThreadGroup();
1356        final String tGroupName = "Test group";
1357
1358        // Our own subclass
1359        class MyThreadGroup extends ThreadGroup {
1360            // Have to define a constructor since there's no default one
1361            public MyThreadGroup(ThreadGroup parent, String name) {
1362                super(parent, name);
1363            }
1364        }
1365        ;
1366
1367        ThreadGroup testRoot = new MyThreadGroup(originalCurrent, tGroupName);
1368        final String toString = testRoot.toString();
1369
1370        StringBuffer expectedResult = new StringBuffer();
1371        expectedResult.append(testRoot.getClass().getName());
1372        expectedResult.append("[name=");
1373        expectedResult.append(tGroupName);
1374        expectedResult.append(",maxpri=");
1375        expectedResult.append(testRoot.getMaxPriority());
1376        expectedResult.append("]");
1377
1378        String expectedValue = expectedResult.toString();
1379
1380        assertTrue("toString does not follow the Java language spec.", toString
1381                .equals(expectedValue));
1382
1383        testRoot.destroy();
1384    }
1385
1386    /**
1387     * @tests java.lang.ThreadGroup#uncaughtException(java.lang.Thread,
1388     *        java.lang.Throwable)
1389     */
1390    @TestTargetNew(
1391        level = TestLevel.COMPLETE,
1392        notes = "",
1393        method = "uncaughtException",
1394        args = {java.lang.Thread.class, java.lang.Throwable.class}
1395    )
1396    @SuppressWarnings("deprecation")
1397    public void test_uncaughtExceptionLjava_lang_ThreadLjava_lang_Throwable() {
1398        // Test for method void
1399        // java.lang.ThreadGroup.uncaughtException(java.lang.Thread,
1400        // java.lang.Throwable)
1401
1402        final ThreadGroup originalCurrent = getInitialThreadGroup();
1403
1404        // indices for the array defined below
1405        final int TEST_DEATH = 0;
1406        final int TEST_OTHER = 1;
1407        final int TEST_EXCEPTION_IN_UNCAUGHT = 2;
1408        final int TEST_OTHER_THEN_DEATH = 3;
1409        final int TEST_FORCING_THROW_THREAD_DEATH = 4;
1410        final int TEST_KILLING = 5;
1411        final int TEST_DEATH_AFTER_UNCAUGHT = 6;
1412
1413        final boolean[] passed = new boolean[] { false, false, false, false,
1414                false, false, false };
1415
1416        ThreadGroup testRoot;
1417        Thread thread;
1418
1419        // Our own exception class
1420        class TestException extends RuntimeException {
1421            private static final long serialVersionUID = 1L;
1422        }
1423
1424        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1425        // - - - - - - -
1426        testRoot = new ThreadGroup(originalCurrent,
1427                "Test Forcing a throw of ThreadDeath") {
1428            @Override
1429            public void uncaughtException(Thread t, Throwable e) {
1430                if (e instanceof ThreadDeath) {
1431                    passed[TEST_FORCING_THROW_THREAD_DEATH] = true;
1432                }
1433                // always forward, any exception
1434                super.uncaughtException(t, e);
1435            }
1436        };
1437
1438        // Test if a Thread tells its ThreadGroup about ThreadDeath
1439        thread = new Thread(testRoot, null, "suicidal thread") {
1440            @Override
1441            public void run() {
1442                throw new ThreadDeath();
1443            }
1444        };
1445        thread.start();
1446        try {
1447            thread.join();
1448        } catch (InterruptedException ie) {
1449            fail("Should not have been interrupted");
1450        }
1451        testRoot.destroy();
1452        assertTrue(
1453                "Any thread should notify its ThreadGroup about its own death, even if suicide:"
1454                        + testRoot, passed[TEST_FORCING_THROW_THREAD_DEATH]);
1455        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1456        // - - - - - - -
1457
1458        testRoot = new ThreadGroup(originalCurrent, "Test ThreadDeath") {
1459            @Override
1460            public void uncaughtException(Thread t, Throwable e) {
1461                passed[TEST_DEATH] = false;
1462                // always forward, any exception
1463                super.uncaughtException(t, e);
1464            }
1465        };
1466
1467        // Test if a Thread tells its ThreadGroup about ThreadDeath
1468        passed[TEST_DEATH] = true;
1469        thread = new Thread(testRoot, null, "no-op thread");
1470        thread.start();
1471        try {
1472            thread.join();
1473        } catch (InterruptedException ie) {
1474            fail("Should not have been interrupted");
1475        }
1476        testRoot.destroy();
1477        assertTrue("A thread should not call uncaughtException when it dies:"
1478                + testRoot, passed[TEST_DEATH]);
1479        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1480        // - - - - - - -
1481
1482        testRoot = new ThreadGroup(originalCurrent, "Test other Exception") {
1483            @Override
1484            public void uncaughtException(Thread t, Throwable e) {
1485                if (e instanceof TestException) {
1486                    passed[TEST_OTHER] = true;
1487                } else {
1488                    // only forward exceptions other than our test
1489                    super.uncaughtException(t, e);
1490                }
1491            }
1492        };
1493
1494        // Test if a Thread tells its ThreadGroup about an Exception
1495        thread = new Thread(testRoot, null, "no-op thread") {
1496            @Override
1497            public void run() {
1498                throw new TestException();
1499            }
1500        };
1501        thread.start();
1502        try {
1503            thread.join();
1504        } catch (InterruptedException ie) {
1505            fail("Should not have been interrupted");
1506        }
1507        testRoot.destroy();
1508        assertTrue(
1509                "Any thread should notify its ThreadGroup about an uncaught exception:"
1510                        + testRoot, passed[TEST_OTHER]);
1511        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1512        // - - - - - - -
1513
1514        // Our own uncaught exception class
1515        class UncaughtException extends TestException {
1516            private static final long serialVersionUID = 1L;
1517        }
1518
1519        testRoot = new ThreadGroup(originalCurrent,
1520                "Test Exception in uncaught exception") {
1521            @Override
1522            public void uncaughtException(Thread t, Throwable e) {
1523                if (e instanceof TestException) {
1524                    passed[TEST_EXCEPTION_IN_UNCAUGHT] = true;
1525                    // Let's simulate an error inside our uncaughtException
1526                    // method.
1527                    // This should be no-op according to the spec
1528                    throw new UncaughtException();
1529                }
1530                // only forward exceptions other than our test
1531                super.uncaughtException(t, e);
1532            }
1533        };
1534
1535        // Test if an Exception in uncaughtException is really a no-op
1536        thread = new Thread(testRoot, null, "no-op thread") {
1537            @Override
1538            public void run() {
1539                try {
1540                    throw new TestException();
1541                } catch (UncaughtException ue) {
1542                    // any exception in my ThreadGroup's uncaughtException must
1543                    // not be propagated.
1544                    // If it gets propagated and we detected that, the test failed
1545                    passed[TEST_EXCEPTION_IN_UNCAUGHT] = false;
1546                }
1547            }
1548        };
1549        thread.start();
1550        try {
1551            thread.join();
1552        } catch (InterruptedException ie) {
1553            fail("Should not have been interrupted");
1554        }
1555        testRoot.destroy();
1556        assertTrue(
1557                "Any uncaughtException in uncaughtException should be no-op:"
1558                        + testRoot, passed[TEST_EXCEPTION_IN_UNCAUGHT]);
1559        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1560        // - - - - - - -
1561
1562        // This is a mix of 2 of the tests above. It is assumed that ThreadDeath
1563        // and any random exception do work , tested separately. Now we test
1564        // if after an uncaughtException is forwarded to the ThreadGroup and
1565        // the Thread dies, if ThreadDeath is also forwarded. It should be
1566        // (so that a ThreadGroup can know its Thread died)
1567        testRoot = new ThreadGroup(originalCurrent,
1568                "Test Uncaught followed by ThreadDeath") {
1569            @Override
1570            public void uncaughtException(Thread t, Throwable e) {
1571                if (e instanceof ThreadDeath) {
1572                    passed[TEST_DEATH_AFTER_UNCAUGHT] = true;
1573                }
1574                if (e instanceof TestException) {
1575                    passed[TEST_OTHER_THEN_DEATH] = true;
1576                } else {
1577                    // only forward exceptions other than our test
1578                    super.uncaughtException(t, e);
1579                }
1580            }
1581        };
1582
1583        // Test if a Thread tells its ThreadGroup about an Exception and also
1584        // ThreadDeath
1585        thread = new Thread(testRoot, null, "no-op thread") {
1586            @Override
1587            public void run() {
1588                throw new TestException();
1589            }
1590        };
1591        thread.start();
1592        try {
1593            thread.join();
1594        } catch (InterruptedException ie) {
1595            fail("Should not have been interrupted");
1596        }
1597        testRoot.destroy();
1598    }
1599
1600    /*
1601     * @see java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable)
1602     */
1603    public void uncaughtException(Thread t, Throwable e) {
1604        interrupted = true;
1605        Thread.setDefaultUncaughtExceptionHandler(null);
1606    }
1607
1608    @Override
1609    protected void setUp() {
1610        initialThreadGroup = Thread.currentThread().getThreadGroup();
1611        rootThreadGroup = initialThreadGroup;
1612        while (rootThreadGroup.getParent() != null) {
1613            rootThreadGroup = rootThreadGroup.getParent();
1614        }
1615    }
1616
1617    @Override
1618    protected void tearDown() {
1619        try {
1620            // Give the threads a chance to die.
1621            Thread.sleep(50);
1622        } catch (InterruptedException e) {
1623        }
1624    }
1625
1626    private Thread[] threads(ThreadGroup parent) {
1627        // No API to get the count of immediate children only ?
1628        int count = parent.activeCount();
1629        Thread[] all = new Thread[count];
1630        int actualSize = parent.enumerate(all, false);
1631        Thread[] result;
1632        if (actualSize == all.length) {
1633            result = all;
1634        } else {
1635            result = new Thread[actualSize];
1636            System.arraycopy(all, 0, result, 0, actualSize);
1637        }
1638
1639        return result;
1640
1641    }
1642
1643    private ThreadGroup getInitialThreadGroup() {
1644        return initialThreadGroup;
1645    }
1646
1647    private ThreadGroup[] allGroups(ThreadGroup parent) {
1648        int count = parent.activeGroupCount();
1649        ThreadGroup[] all = new ThreadGroup[count];
1650        parent.enumerate(all, true);
1651        return all;
1652    }
1653
1654    private void daemonTests() {
1655        // Test for method void java.lang.ThreadGroup.setDaemon(boolean)
1656
1657        final ThreadGroup originalCurrent = getInitialThreadGroup();
1658        final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
1659                "Test group");
1660
1661        testRoot.setDaemon(true);
1662        assertTrue("Setting daemon&getting does not work", testRoot.isDaemon());
1663
1664        testRoot.setDaemon(false);
1665        assertTrue("Setting daemon&getting does not work", !testRoot.isDaemon());
1666
1667        testRoot.destroy();
1668    }
1669
1670    private boolean wipeAllThreads(final ThreadGroup aGroup) {
1671        boolean ok = true;
1672        Thread[] threads = threads(aGroup);
1673        for (Thread t : threads) {
1674            ok = ok && wipeThread(t);
1675        }
1676
1677        // Recursively for subgroups (if any)
1678        ThreadGroup[] children = groups(aGroup);
1679        for (ThreadGroup element : children) {
1680            ok = ok && wipeAllThreads(element);
1681        }
1682        return ok;
1683    }
1684
1685    private boolean wipeSideEffectThreads(ThreadGroup aGroup) {
1686        boolean ok = true;
1687        Thread[] threads = threads(aGroup);
1688        for (Thread t : threads) {
1689            if (t.getName().equals("SimpleThread")
1690                    || t.getName().equals("Bogus Name")
1691                    || t.getName().equals("Testing")
1692                    || t.getName().equals("foo")
1693                    || t.getName().equals("Test Group")
1694                    || t.getName().equals("Squawk")
1695                    || t.getName().equals("Thread-1")
1696                    || t.getName().equals("firstOne")
1697                    || t.getName().equals("secondOne")
1698                    || t.getName().equals("Thread-16")
1699                    || t.getName().equals("Thread-14")) {
1700                ok = ok && wipeThread(t);
1701            }
1702        }
1703
1704        // Recursively for subgroups (if any)
1705        ThreadGroup[] children = groups(aGroup);
1706
1707        for (ThreadGroup element : children) {
1708            ok = ok && wipeSideEffectThreads(element);
1709            if(element.getName() !=  null) {
1710                if (element.getName().equals("Test Group")
1711                    || element.getName().equals("foo")
1712                    || element.getName().equals("jp")) {
1713                    element.destroy();
1714                }
1715            }
1716        }
1717        try {
1718            // Give the threads a chance to die.
1719            Thread.sleep(50);
1720        } catch (InterruptedException e) {
1721        }
1722        return ok;
1723    }
1724
1725    private void asyncBuildRandomTreeUnder(final ThreadGroup aGroup,
1726            final int depth, final Vector<ThreadGroup> allCreated) {
1727        if (depth <= 0) {
1728            return;
1729        }
1730
1731        final int maxImmediateSubgroups = random(3);
1732        for (int i = 0; i < maxImmediateSubgroups; i++) {
1733            final int iClone = i;
1734            final String name = " Depth = " + depth + ",N = " + iClone
1735                    + ",Vector size at creation: " + allCreated.size();
1736            // Use concurrency to maximize chance of exposing concurrency bugs
1737            // in ThreadGroups
1738            Thread t = new Thread(aGroup, name) {
1739                @Override
1740                public void run() {
1741                    ThreadGroup newGroup = new ThreadGroup(aGroup, name);
1742                    allCreated.addElement(newGroup);
1743                    asyncBuildRandomTreeUnder(newGroup, depth - 1, allCreated);
1744                }
1745            };
1746            t.start();
1747        }
1748
1749    }
1750
1751    private Vector<ThreadGroup> asyncBuildRandomTreeUnder(final ThreadGroup aGroup,
1752            final int depth) {
1753        Vector<ThreadGroup> result = new Vector<ThreadGroup>();
1754        asyncBuildRandomTreeUnder(aGroup, depth, result);
1755        return result;
1756
1757    }
1758
1759    private boolean allSuspended(Vector<MyThread> threads) {
1760        for (int i = 0; i < threads.size(); i++) {
1761            MyThread t = threads.elementAt(i);
1762            if (t.isActivelyRunning()) {
1763                return false;
1764            }
1765        }
1766
1767        return true;
1768
1769    }
1770
1771    private ThreadGroup[] groups(ThreadGroup parent) {
1772        // No API to get the count of immediate children only ?
1773        int count = parent.activeGroupCount();
1774        ThreadGroup[] all = new ThreadGroup[count];
1775        parent.enumerate(all, false);
1776        // Now we may have nulls in the array, we must find the actual size
1777        int actualSize = 0;
1778        for (; actualSize < all.length; actualSize++) {
1779            if (all[actualSize] == null) {
1780                break;
1781            }
1782        }
1783        ThreadGroup[] result;
1784        if (actualSize == all.length) {
1785            result = all;
1786        } else {
1787            result = new ThreadGroup[actualSize];
1788            System.arraycopy(all, 0, result, 0, actualSize);
1789        }
1790
1791        return result;
1792
1793    }
1794
1795    private Vector<MyThread> populateGroupsWithThreads(final ThreadGroup aGroup,
1796            final int threadCount) {
1797        Vector<MyThread> result = new Vector<MyThread>();
1798        populateGroupsWithThreads(aGroup, threadCount, result);
1799        return result;
1800
1801    }
1802
1803    private void populateGroupsWithThreads(final ThreadGroup aGroup,
1804            final int threadCount, final Vector<MyThread> allCreated) {
1805        for (int i = 0; i < threadCount; i++) {
1806            final int iClone = i;
1807            final String name = "(MyThread)N =" + iClone + "/" + threadCount
1808                    + " ,Vector size at creation: " + allCreated.size();
1809
1810            MyThread t = new MyThread(aGroup, name);
1811            allCreated.addElement(t);
1812        }
1813
1814        // Recursively for subgroups (if any)
1815        ThreadGroup[] children = groups(aGroup);
1816        for (ThreadGroup element : children) {
1817            populateGroupsWithThreads(element, threadCount, allCreated);
1818        }
1819
1820    }
1821
1822    private int random(int max) {
1823
1824        return 1 + ((new Object()).hashCode() % max);
1825
1826    }
1827
1828    @SuppressWarnings("deprecation")
1829    private boolean wipeThread(Thread t) {
1830        t.stop();
1831        try {
1832            t.join(1000);
1833        } catch (InterruptedException ie) {
1834            fail("Should not have been interrupted");
1835        }
1836        // The thread had plenty (subjective) of time to die so there
1837        // is a problem.
1838        if (t.isAlive()) {
1839            return false;
1840        }
1841
1842        return true;
1843    }
1844
1845    private Vector<ThreadGroup> buildRandomTreeUnder(ThreadGroup aGroup, int depth) {
1846        Vector<ThreadGroup> result = asyncBuildRandomTreeUnder(aGroup, depth);
1847        while (true) {
1848            int sizeBefore = result.size();
1849            try {
1850                Thread.sleep(1000);
1851                int sizeAfter = result.size();
1852                // If no activity for a while, we assume async building may be
1853                // done.
1854                if (sizeBefore == sizeAfter) {
1855                    // It can only be done if no more threads. Unfortunately we
1856                    // are relying on this API to work as well.
1857                    // If it does not, we may loop forever.
1858                    if (aGroup.activeCount() == 0) {
1859                        break;
1860                    }
1861                }
1862            } catch (InterruptedException e) {
1863            }
1864        }
1865        return result;
1866
1867    }
1868
1869    private boolean arrayIncludes(Object[] array, Object toTest) {
1870        for (Object element : array) {
1871            if (element == toTest) {
1872                return true;
1873            }
1874        }
1875
1876        return false;
1877    }
1878
1879    protected void myassertTrue(String msg, boolean b) {
1880        // This method is defined here just to solve a visibility problem
1881        // of protected methods with inner types
1882        assertTrue(msg, b);
1883    }
1884
1885    private ThreadGroup getRootThreadGroup() {
1886        return rootThreadGroup;
1887
1888    }
1889
1890    SecurityManager sm = new SecurityManager() {
1891
1892        public void checkPermission(Permission perm) {
1893        }
1894
1895        public void checkAccess(ThreadGroup g) {
1896           throw new SecurityException();
1897        }
1898    };
1899}
1900