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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org.apache.harmony.luni.tests.java.lang;
20 import java.util.Vector;
22 // BEGIN android-changed
23 public class ThreadGroupTest extends junit.framework.TestCase implements Thread.UncaughtExceptionHandler {
24 // END android-changed
26 class MyThread extends Thread {
27 public volatile int heartBeat = 0;
29 public MyThread(ThreadGroup group, String name)
30 throws SecurityException, IllegalThreadStateException {
40 } catch (InterruptedException e) {
45 public boolean isActivelyRunning() {
47 return isActivelyRunning(MAX_WAIT);
50 public boolean isActivelyRunning(long maxWait) {
52 long start = System.currentTimeMillis();
55 int beat2 = heartBeat;
59 } while (System.currentTimeMillis() - start < maxWait);
65 private ThreadGroup rootThreadGroup = null;
67 private ThreadGroup initialThreadGroup = null;
70 * @tests java.lang.ThreadGroup#ThreadGroup(java.lang.String)
72 public void test_ConstructorLjava_lang_String() {
73 // Test for method java.lang.ThreadGroup(java.lang.String)
75 // Unfortunately we have to use other APIs as well as we test the
78 ThreadGroup newGroup = null;
79 ThreadGroup initial = getInitialThreadGroup();
80 final String name = "Test name";
81 newGroup = new ThreadGroup(name);
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));
93 * @tests java.lang.ThreadGroup#ThreadGroup(java.lang.ThreadGroup,
96 public void test_ConstructorLjava_lang_ThreadGroupLjava_lang_String() {
97 // Test for method java.lang.ThreadGroup(java.lang.ThreadGroup,
100 // Unfortunately we have to use other APIs as well as we test the
103 ThreadGroup newGroup = null;
106 newGroup = new ThreadGroup(null, null);
107 } catch (NullPointerException e) {
109 assertNull("Can't create a ThreadGroup with a null parent",
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());
116 // Lets start all over
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());
123 // Lets start all over
127 newGroup = new ThreadGroup(newGroup, "a name here");
128 } catch (IllegalThreadStateException e) {
132 assertNull("Can't create a subgroup of a destroyed group",
137 * @tests java.lang.ThreadGroup#activeCount()
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() {
146 } catch (InterruptedException e) {
150 int count = tg.activeCount();
151 assertTrue("wrong active count: " + count, count == 0);
153 count = tg.activeCount();
154 assertTrue("wrong active count: " + count, count == 1);
158 } catch (InterruptedException e) {
164 // BEGIN android-added
166 * @tests java.lang.ThreadGroup#activeGroupCount()
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() {
174 // TODO Auto-generated method stub
177 assertEquals("Incorrect number of groups",
178 0, tg.activeGroupCount());
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());
191 * @tests java.lang.ThreadGroup#allowThreadSuspension(boolean)
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));
204 * @tests java.lang.ThreadGroup#checkAccess()
206 public void test_checkAccess() {
207 // Test for method void java.lang.ThreadGroup.checkAccess()
209 final ThreadGroup originalCurrent = getInitialThreadGroup();
210 ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
212 SecurityManager currentManager = System.getSecurityManager();
213 boolean passed = true;
216 if (currentManager != null) {
217 testRoot.checkAccess();
219 } catch (SecurityException se) {
223 assertTrue("CheckAccess is no-op with no SecurityManager", passed);
230 * @tests java.lang.ThreadGroup#destroy()
232 public void test_destroy() {
233 // Test for method void java.lang.ThreadGroup.destroy()
235 final ThreadGroup originalCurrent = getInitialThreadGroup();
236 ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
238 final Vector<ThreadGroup> subgroups = buildRandomTreeUnder(testRoot, DEPTH);
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
247 boolean passed = false;
250 } catch (IllegalThreadStateException e) {
254 assertTrue("Destroyed child can't be destroyed again", passed);
257 testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
258 testRoot.setDaemon(true);
260 ThreadGroup child = new ThreadGroup(testRoot, "daemon child");
262 // If we destroy the last daemon's child, the daemon should get destroyed
266 boolean passed = false;
269 } catch (IllegalThreadStateException e) {
273 assertTrue("Daemon should have been destroyed already", passed);
278 } catch (IllegalThreadStateException e) {
282 assertTrue("Daemon parent should have been destroyed automatically",
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));
291 testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
292 testRoot.setDaemon(true);
293 Thread noOp = new Thread(testRoot, null, "no-op thread") {
300 // Wait for the no-op thread to run inside daemon ThreadGroup
303 } catch (InterruptedException ie) {
304 fail("Should not be interrupted");
311 } catch (IllegalThreadStateException e) {
316 "Daemon group should have been destroyed already when last thread died",
319 testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
320 noOp = new Thread(testRoot, null, "no-op thread") {
325 } catch (InterruptedException ie) {
326 fail("Should not be interrupted");
331 // Has to execute the next lines in an interval < the sleep interval of
337 } catch (IllegalThreadStateException its) {
340 assertTrue("Can't destroy a ThreadGroup that has threads", passed);
342 // But after the thread dies, we have to be able to destroy the thread
346 } catch (InterruptedException ie) {
347 fail("Should not be interrupted");
353 } catch (IllegalThreadStateException its) {
357 "Should be able to destroy a ThreadGroup that has no threads",
363 * @tests java.lang.ThreadGroup#destroy()
365 public void test_destroy_subtest0() {
366 ThreadGroup group1 = new ThreadGroup("test_destroy_subtest0");
369 new Thread(group1, "test_destroy_subtest0");
370 fail("should throw IllegalThreadStateException");
371 } catch (IllegalThreadStateException e) {
376 * @tests java.lang.ThreadGroup#getMaxPriority()
378 public void test_getMaxPriority() {
379 // Test for method int java.lang.ThreadGroup.getMaxPriority()
381 final ThreadGroup originalCurrent = getInitialThreadGroup();
382 ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
384 boolean passed = true;
386 testRoot.setMaxPriority(Thread.MIN_PRIORITY);
387 } catch (IllegalArgumentException iae) {
390 assertTrue("Should be able to set priority", passed);
392 assertTrue("New value should be the same as we set", testRoot
393 .getMaxPriority() == Thread.MIN_PRIORITY);
400 * @tests java.lang.ThreadGroup#getName()
402 public void test_getName() {
403 // Test for method java.lang.String java.lang.ThreadGroup.getName()
405 final ThreadGroup originalCurrent = getInitialThreadGroup();
406 final String name = "Test group";
407 final ThreadGroup testRoot = new ThreadGroup(originalCurrent, name);
409 assertTrue("Setting a name&getting does not work", testRoot.getName()
417 * @tests java.lang.ThreadGroup#getParent()
419 public void test_getParent() {
420 // Test for method java.lang.ThreadGroup
421 // java.lang.ThreadGroup.getParent()
423 final ThreadGroup originalCurrent = getInitialThreadGroup();
424 ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
426 assertTrue("Parent is wrong", testRoot.getParent() == originalCurrent);
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);
436 for (int i = 0; i < TOTAL_DEPTH; i++) {
437 current = new ThreadGroup(current, "level " + i);
438 groups.addElement(current);
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);
448 final ThreadGroup[] checkAccessGroup = new ThreadGroup[1];
449 class SecurityManagerImpl extends MutableSecurityManager {
451 public void checkAccess(ThreadGroup group) {
452 checkAccessGroup[0] = group;
455 SecurityManagerImpl sm = new SecurityManagerImpl();
456 //add permission to allow reset of security manager
457 sm.addPermission(MutableSecurityManager.SET_SECURITY_MANAGER);
461 // To see if it checks Thread creation with our SecurityManager
462 System.setSecurityManager(sm);
463 parent = testRoot.getParent();
465 // restore original, no side-effects
466 System.setSecurityManager(null);
468 assertTrue("checkAccess with incorrect group",
469 checkAccessGroup[0] == parent);
474 // BEGIN android-added
476 * @tests java.lang.ThreadGroup#interrupt()
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() {
486 } catch (InterruptedException e) {
491 assertFalse("Incorrect state of thread", interrupted);
493 assertFalse("Incorrect state of thread", interrupted);
497 } catch (InterruptedException e) {
499 assertTrue("Incorrect state of thread", interrupted);
505 * @tests java.lang.ThreadGroup#isDaemon()
507 public void test_isDaemon() {
508 // Test for method boolean java.lang.ThreadGroup.isDaemon()
514 // BEGIN android-added
516 * @tests java.lang.ThreadGroup#isDestroyed()
518 public void test_isDestroyed() {
519 final ThreadGroup originalCurrent = getInitialThreadGroup();
520 final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
522 assertFalse("Test group is not destroyed yet",
523 testRoot.isDestroyed());
525 assertTrue("Test group already destroyed",
526 testRoot.isDestroyed());
531 * @tests java.lang.ThreadGroup#list()
533 public void test_list() {
534 // Test for method void java.lang.ThreadGroup.list()
536 final ThreadGroup originalCurrent = getInitialThreadGroup();
537 // wipeSideEffectThreads destroy all side effect of threads created in
539 boolean result = wipeSideEffectThreads(originalCurrent);
540 if (result == false) {
541 fail("wipe threads in test_list() not successful");
543 final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
546 // First save the original System.out
547 java.io.PrintStream originalOut = System.out;
550 java.io.ByteArrayOutputStream contentsStream = new java.io.ByteArrayOutputStream(
552 java.io.PrintStream newOut = new java.io.PrintStream(contentsStream);
554 // We have to "redirect" System.out to test the method 'list'
555 System.setOut(newOut);
557 originalCurrent.list();
560 * The output has to look like this
562 * java.lang.ThreadGroup[name=main,maxpri=10] Thread[main,5,main]
563 * java.lang.ThreadGroup[name=Test group,maxpri=10]
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: "
578 // No matter what, we need to restore the original System.out
579 System.setOut(originalOut);
585 * @tests java.lang.ThreadGroup#parentOf(java.lang.ThreadGroup)
587 public void test_parentOfLjava_lang_ThreadGroup() {
588 // Test for method boolean
589 // java.lang.ThreadGroup.parentOf(java.lang.ThreadGroup)
591 final ThreadGroup originalCurrent = getInitialThreadGroup();
592 final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
595 buildRandomTreeUnder(testRoot, DEPTH);
597 final ThreadGroup[] allChildren = allGroups(testRoot);
598 for (ThreadGroup element : allChildren) {
599 assertTrue("Have to be parentOf all children", testRoot
603 assertTrue("Have to be parentOf itself", testRoot.parentOf(testRoot));
606 assertTrue("Parent can't have test group as subgroup anymore",
607 !arrayIncludes(groups(testRoot.getParent()), testRoot));
610 System.setSecurityManager(new MutableSecurityManager(MutableSecurityManager.SET_SECURITY_MANAGER));
611 assertTrue("Should not be parent", !testRoot
612 .parentOf(originalCurrent));
614 System.setSecurityManager(null);
619 * @tests java.lang.ThreadGroup#resume()
621 @SuppressWarnings("deprecation")
622 public void test_resume() throws OutOfMemoryError {
623 // Test for method void java.lang.ThreadGroup.resume()
625 final ThreadGroup originalCurrent = getInitialThreadGroup();
627 final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
630 buildRandomTreeUnder(testRoot, DEPTH);
632 final int THREADS_PER_GROUP = 2;
633 final Vector<MyThread> threads = populateGroupsWithThreads(testRoot,
636 boolean[] isResumed = null;
639 for (int i = 0; i < threads.size(); i++) {
640 Thread t = threads.elementAt(i);
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);
651 t.stop(); // deprecated but effective
656 // Now that they are all suspended, let's resume the ThreadGroup
659 // Give them some time to really resume
662 } catch (InterruptedException ie) {
663 fail("Should not have been interrupted");
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
672 isResumed[i] = t.isActivelyRunning(1000);
673 failed = failed | (!isResumed[i]);
675 t.stop(); // deprecated but effective
678 // Give them some time to really die
681 } catch (InterruptedException ie) {
682 fail("Should not have been interrupted");
685 // Make sure we do cleanup before returning
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]);
694 assertEquals("Method destroy must have problems",
695 0, testRoot.activeCount());
700 * @tests java.lang.ThreadGroup#setDaemon(boolean)
702 public void test_setDaemonZ() {
703 // Test for method void java.lang.ThreadGroup.setDaemon(boolean)
710 * @tests java.lang.ThreadGroup#setMaxPriority(int)
712 public void test_setMaxPriorityI() {
713 // Test for method void java.lang.ThreadGroup.setMaxPriority(int)
715 final ThreadGroup originalCurrent = getInitialThreadGroup();
716 ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
720 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
722 int currentMax = testRoot.getMaxPriority();
723 testRoot.setMaxPriority(Thread.MAX_PRIORITY + 1);
724 passed = testRoot.getMaxPriority() == currentMax;
726 "setMaxPriority: Any value higher than the current one is ignored. Before: "
727 + currentMax + " , after: " + testRoot.getMaxPriority(),
730 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
732 currentMax = testRoot.getMaxPriority();
733 testRoot.setMaxPriority(Thread.MIN_PRIORITY - 1);
734 passed = testRoot.getMaxPriority() == Thread.MIN_PRIORITY;
736 "setMaxPriority: Any value smaller than MIN_PRIORITY is adjusted to MIN_PRIORITY. Before: "
737 + currentMax + " , after: " + testRoot.getMaxPriority(),
740 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
743 testRoot = new ThreadGroup(originalCurrent, "Test group");
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
750 ThreadGroup current = testRoot;
751 for (int i = 0; i < TOTAL_DEPTH; i++) {
752 current = new ThreadGroup(current, "level " + i);
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;
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);
766 for (int i = 0; i < TOTAL_DEPTH; i++) {
767 maxPrio = current.getMaxPriority();
768 parentMaxPrio = current.getParent().getMaxPriority();
770 ThreadGroup[] children = groups(current);
771 assertEquals("Can only have 1 subgroup", 1, children.length);
772 current = children[0];
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);
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);
786 "Priority of leaf child group has to be much smaller than original root group",
787 current.getMaxPriority() == testRoot.getMaxPriority()
792 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
795 testRoot = new ThreadGroup(originalCurrent, "Test group");
797 testRoot.setMaxPriority(Thread.MAX_PRIORITY);
798 } catch (IllegalArgumentException iae) {
802 "Max Priority = Thread.MAX_PRIORITY should be possible if the test is run with default system ThreadGroup as root",
806 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
809 testRoot = new ThreadGroup(originalCurrent, "Test group");
810 System.setSecurityManager(new MutableSecurityManager(MutableSecurityManager.SET_SECURITY_MANAGER));
813 testRoot.setMaxPriority(Thread.MIN_PRIORITY);
814 } catch (IllegalArgumentException iae) {
818 System.setSecurityManager(null);
821 "Min Priority = Thread.MIN_PRIORITY should be possible, always",
826 System.setSecurityManager(new MutableSecurityManager(MutableSecurityManager.SET_SECURITY_MANAGER));
827 originalCurrent.setMaxPriority(Thread.MAX_PRIORITY);
829 System.setSecurityManager(null);
834 * @tests java.lang.ThreadGroup#stop()
836 @SuppressWarnings("deprecation")
837 public void test_stop() throws OutOfMemoryError {
838 // Test for method void java.lang.ThreadGroup.stop()
840 final ThreadGroup originalCurrent = getInitialThreadGroup();
842 final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
845 buildRandomTreeUnder(testRoot, DEPTH);
847 final int THREADS_PER_GROUP = 2;
848 final Vector<MyThread> threads = populateGroupsWithThreads(testRoot,
852 for (int i = 0; i < threads.size(); i++) {
853 Thread t = threads.elementAt(i);
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
864 // Now that they are all running, let's stop the ThreadGroup
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);
876 // We wait 5000 ms per Thread, but due to scheduling it may
877 // take a while to run
879 } catch (InterruptedException ie) {
880 fail("Should not be interrupted");
888 // To make sure that even if we fail, we exit in a clean state
891 assertTrue("Thread should be dead by now", passed);
893 assertEquals("Method destroy (or wipeAllThreads) must have problems",
894 0, testRoot.activeCount());
899 * @tests java.lang.ThreadGroup#suspend()
901 @SuppressWarnings("deprecation")
902 public void test_suspend() throws OutOfMemoryError {
903 // Test for method void java.lang.ThreadGroup.suspend()
905 final ThreadGroup originalCurrent = getInitialThreadGroup();
907 final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
910 buildRandomTreeUnder(testRoot, DEPTH);
912 final int THREADS_PER_GROUP = 2;
913 final Vector<MyThread> threads = populateGroupsWithThreads(testRoot,
916 boolean passed = false;
919 for (int i = 0; i < threads.size(); i++) {
920 Thread t = threads.elementAt(i);
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
931 // Now that they are all running, let's suspend the ThreadGroup
934 passed = allSuspended(threads);
935 assertTrue("Should be able to wipe all threads (allSuspended="
936 + passed + ")", wipeAllThreads(testRoot));
939 // We can't destroy a ThreadGroup if we do not make sure it has no
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) {
949 } catch (InterruptedException e) {
950 fail("unexpected interruption");
954 fail("stop() has not stopped threads in ThreadGroup 'testRoot'");
957 // Make sure we cleanup before returning from the method
960 assertTrue("All threads should be suspended", passed);
962 assertEquals("Method destroy (or wipeAllThreads) must have problems",
963 0, testRoot.activeCount());
968 * @tests java.lang.ThreadGroup#toString()
970 public void test_toString() {
971 // Test for method java.lang.String java.lang.ThreadGroup.toString()
973 final ThreadGroup originalCurrent = getInitialThreadGroup();
974 final String tGroupName = "Test group";
977 class MyThreadGroup extends ThreadGroup {
978 // Have to define a constructor since there's no default one
979 public MyThreadGroup(ThreadGroup parent, String name) {
985 ThreadGroup testRoot = new MyThreadGroup(originalCurrent, tGroupName);
986 final String toString = testRoot.toString();
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("]");
996 String expectedValue = expectedResult.toString();
998 assertTrue("toString does not follow the Java language spec.", toString
999 .equals(expectedValue));
1005 * @tests java.lang.ThreadGroup#uncaughtException(java.lang.Thread,
1006 * java.lang.Throwable)
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)
1014 final ThreadGroup originalCurrent = getInitialThreadGroup();
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;
1025 final boolean[] passed = new boolean[] { false, false, false, false,
1026 false, false, false };
1028 ThreadGroup testRoot;
1031 // Our own exception class
1032 class TestException extends RuntimeException {
1033 private static final long serialVersionUID = 1L;
1036 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1038 testRoot = new ThreadGroup(originalCurrent,
1039 "Test killing a Thread, forcing it to throw ThreadDeath") {
1041 public void uncaughtException(Thread t, Throwable e) {
1042 if (e instanceof ThreadDeath) {
1043 passed[TEST_KILLING] = true;
1045 // always forward, any exception
1046 super.uncaughtException(t, e);
1050 // Test if a Thread tells its ThreadGroup about ThreadDeath
1051 thread = new Thread(testRoot, null, "victim thread (to be killed)") {
1062 } catch (InterruptedException ie) {
1063 fail("Should not have been interrupted");
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
1074 } catch (InterruptedException ie) {
1075 fail("Should not have been interrupted");
1079 } catch (InterruptedException ie) {
1080 fail("Should not have been interrupted");
1084 "Any thread should notify its ThreadGroup about its own death, even if killed:"
1085 + testRoot, passed[TEST_KILLING]);
1087 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1089 testRoot = new ThreadGroup(originalCurrent,
1090 "Test Forcing a throw of ThreadDeath") {
1092 public void uncaughtException(Thread t, Throwable e) {
1093 if (e instanceof ThreadDeath) {
1094 passed[TEST_FORCING_THROW_THREAD_DEATH] = true;
1096 // always forward, any exception
1097 super.uncaughtException(t, e);
1101 // Test if a Thread tells its ThreadGroup about ThreadDeath
1102 thread = new Thread(testRoot, null, "suicidal thread") {
1105 throw new ThreadDeath();
1111 } catch (InterruptedException ie) {
1112 fail("Should not have been interrupted");
1116 "Any thread should notify its ThreadGroup about its own death, even if suicide:"
1117 + testRoot, passed[TEST_FORCING_THROW_THREAD_DEATH]);
1119 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1122 testRoot = new ThreadGroup(originalCurrent, "Test ThreadDeath") {
1124 public void uncaughtException(Thread t, Throwable e) {
1125 passed[TEST_DEATH] = false;
1126 // always forward, any exception
1127 super.uncaughtException(t, e);
1131 // Test if a Thread tells its ThreadGroup about ThreadDeath
1132 passed[TEST_DEATH] = true;
1133 thread = new Thread(testRoot, null, "no-op thread");
1137 } catch (InterruptedException ie) {
1138 fail("Should not have been interrupted");
1141 assertTrue("A thread should not call uncaughtException when it dies:"
1142 + testRoot, passed[TEST_DEATH]);
1144 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1147 testRoot = new ThreadGroup(originalCurrent, "Test other Exception") {
1149 public void uncaughtException(Thread t, Throwable e) {
1150 if (e instanceof TestException) {
1151 passed[TEST_OTHER] = true;
1153 // only forward exceptions other than our test
1154 super.uncaughtException(t, e);
1159 // Test if a Thread tells its ThreadGroup about an Exception
1160 thread = new Thread(testRoot, null, "no-op thread") {
1163 throw new TestException();
1169 } catch (InterruptedException ie) {
1170 fail("Should not have been interrupted");
1174 "Any thread should notify its ThreadGroup about an uncaught exception:"
1175 + testRoot, passed[TEST_OTHER]);
1177 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1180 // Our own uncaught exception class
1181 class UncaughtException extends TestException {
1182 private static final long serialVersionUID = 1L;
1185 testRoot = new ThreadGroup(originalCurrent,
1186 "Test Exception in uncaught exception") {
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
1193 // This should be no-op according to the spec
1194 throw new UncaughtException();
1196 // only forward exceptions other than our test
1197 super.uncaughtException(t, e);
1201 // Test if an Exception in uncaughtException is really a no-op
1202 thread = new Thread(testRoot, null, "no-op thread") {
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;
1218 } catch (InterruptedException ie) {
1219 fail("Should not have been interrupted");
1223 "Any uncaughtException in uncaughtException should be no-op:"
1224 + testRoot, passed[TEST_EXCEPTION_IN_UNCAUGHT]);
1226 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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") {
1237 public void uncaughtException(Thread t, Throwable e) {
1238 if (e instanceof ThreadDeath) {
1239 passed[TEST_DEATH_AFTER_UNCAUGHT] = true;
1241 if (e instanceof TestException) {
1242 passed[TEST_OTHER_THEN_DEATH] = true;
1244 // only forward exceptions other than our test
1245 super.uncaughtException(t, e);
1250 // Test if a Thread tells its ThreadGroup about an Exception and also
1252 thread = new Thread(testRoot, null, "no-op thread") {
1255 throw new TestException();
1261 } catch (InterruptedException ie) {
1262 fail("Should not have been interrupted");
1267 // BEGIN android-added
1269 * @see java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable)
1271 public void uncaughtException(Thread t, Throwable e) {
1273 Thread.setDefaultUncaughtExceptionHandler(null);
1275 // END android-added
1278 protected void setUp() {
1279 initialThreadGroup = Thread.currentThread().getThreadGroup();
1280 rootThreadGroup = initialThreadGroup;
1281 while (rootThreadGroup.getParent() != null) {
1282 rootThreadGroup = rootThreadGroup.getParent();
1287 protected void tearDown() {
1289 // Give the threads a chance to die.
1291 } catch (InterruptedException e) {
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);
1301 if (actualSize == all.length) {
1304 result = new Thread[actualSize];
1305 System.arraycopy(all, 0, result, 0, actualSize);
1312 private ThreadGroup getInitialThreadGroup() {
1313 return initialThreadGroup;
1316 private ThreadGroup[] allGroups(ThreadGroup parent) {
1317 int count = parent.activeGroupCount();
1318 ThreadGroup[] all = new ThreadGroup[count];
1319 parent.enumerate(all, true);
1323 private void daemonTests() {
1324 // Test for method void java.lang.ThreadGroup.setDaemon(boolean)
1326 final ThreadGroup originalCurrent = getInitialThreadGroup();
1327 final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
1330 testRoot.setDaemon(true);
1331 assertTrue("Setting daemon&getting does not work", testRoot.isDaemon());
1333 testRoot.setDaemon(false);
1334 assertTrue("Setting daemon&getting does not work", !testRoot.isDaemon());
1340 private boolean wipeAllThreads(final ThreadGroup aGroup) {
1342 Thread[] threads = threads(aGroup);
1343 for (Thread t : threads) {
1344 ok = ok && wipeThread(t);
1347 // Recursively for subgroups (if any)
1348 ThreadGroup[] children = groups(aGroup);
1349 for (ThreadGroup element : children) {
1350 ok = ok && wipeAllThreads(element);
1357 private boolean wipeSideEffectThreads(ThreadGroup aGroup) {
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);
1376 // Recursively for subgroups (if any)
1377 ThreadGroup[] children = groups(aGroup);
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")) {
1388 // Give the threads a chance to die.
1390 } catch (InterruptedException e) {
1395 private void asyncBuildRandomTreeUnder(final ThreadGroup aGroup,
1396 final int depth, final Vector<ThreadGroup> allCreated) {
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
1408 Thread t = new Thread(aGroup, name) {
1411 ThreadGroup newGroup = new ThreadGroup(aGroup, name);
1412 allCreated.addElement(newGroup);
1413 asyncBuildRandomTreeUnder(newGroup, depth - 1, allCreated);
1421 private Vector<ThreadGroup> asyncBuildRandomTreeUnder(final ThreadGroup aGroup,
1423 Vector<ThreadGroup> result = new Vector<ThreadGroup>();
1424 asyncBuildRandomTreeUnder(aGroup, depth, result);
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()) {
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
1448 for (; actualSize < all.length; actualSize++) {
1449 if (all[actualSize] == null) {
1453 ThreadGroup[] result;
1454 if (actualSize == all.length) {
1457 result = new ThreadGroup[actualSize];
1458 System.arraycopy(all, 0, result, 0, actualSize);
1465 private Vector<MyThread> populateGroupsWithThreads(final ThreadGroup aGroup,
1466 final int threadCount) {
1467 Vector<MyThread> result = new Vector<MyThread>();
1468 populateGroupsWithThreads(aGroup, threadCount, result);
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();
1480 MyThread t = new MyThread(aGroup, name);
1481 allCreated.addElement(t);
1484 // Recursively for subgroups (if any)
1485 ThreadGroup[] children = groups(aGroup);
1486 for (ThreadGroup element : children) {
1487 populateGroupsWithThreads(element, threadCount, allCreated);
1492 private int random(int max) {
1494 return 1 + ((new Object()).hashCode() % max);
1498 @SuppressWarnings("deprecation")
1499 private boolean wipeThread(Thread t) {
1503 } catch (InterruptedException ie) {
1504 fail("Should not have been interrupted");
1506 // The thread had plenty (subjective) of time to die so there
1515 private Vector<ThreadGroup> buildRandomTreeUnder(ThreadGroup aGroup, int depth) {
1516 Vector<ThreadGroup> result = asyncBuildRandomTreeUnder(aGroup, depth);
1518 int sizeBefore = result.size();
1521 int sizeAfter = result.size();
1522 // If no activity for a while, we assume async building may be
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) {
1532 } catch (InterruptedException e) {
1539 private boolean arrayIncludes(Object[] array, Object toTest) {
1540 for (Object element : array) {
1541 if (element == toTest) {
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
1555 private ThreadGroup getRootThreadGroup() {
1556 return rootThreadGroup;