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