OSDN Git Service

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