Home | History | Annotate | Download | only in lang
      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 public class ThreadGroupTest extends junit.framework.TestCase {
     23 
     24 	class MyThread extends Thread {
     25 		public volatile int heartBeat = 0;
     26 
     27 		public MyThread(ThreadGroup group, String name)
     28 				throws SecurityException, IllegalThreadStateException {
     29 			super(group, name);
     30 		}
     31 
     32 		@Override
     33         public void run() {
     34 			while (true) {
     35 				heartBeat++;
     36 				try {
     37 					Thread.sleep(50);
     38 				} catch (InterruptedException e) {
     39 				}
     40 			}
     41 		}
     42 
     43 		public boolean isActivelyRunning() {
     44 			long MAX_WAIT = 100;
     45 			return isActivelyRunning(MAX_WAIT);
     46 		}
     47 
     48 		public boolean isActivelyRunning(long maxWait) {
     49 			int beat = heartBeat;
     50 			long start = System.currentTimeMillis();
     51 			do {
     52 				Thread.yield();
     53 				int beat2 = heartBeat;
     54 				if (beat != beat2) {
     55                     return true;
     56                 }
     57 			} while (System.currentTimeMillis() - start < maxWait);
     58 			return false;
     59 		}
     60 
     61 	}
     62 
     63 	private ThreadGroup rootThreadGroup = null;
     64 
     65 	private ThreadGroup initialThreadGroup = null;
     66 
     67 	/**
     68 	 * @tests java.lang.ThreadGroup#ThreadGroup(java.lang.String)
     69 	 */
     70 	public void test_ConstructorLjava_lang_String() {
     71 		// Test for method java.lang.ThreadGroup(java.lang.String)
     72 
     73 		// Unfortunately we have to use other APIs as well as we test the
     74 		// constructor
     75 
     76 		ThreadGroup newGroup = null;
     77 		ThreadGroup initial = getInitialThreadGroup();
     78 		final String name = "Test name";
     79 		newGroup = new ThreadGroup(name);
     80 		assertTrue(
     81 				"Has to be possible to create a subgroup of current group using simple constructor",
     82 				newGroup.getParent() == initial);
     83 		assertTrue("Name has to be correct", newGroup.getName().equals(name));
     84 
     85 		// cleanup
     86 		newGroup.destroy();
     87 
     88 	}
     89 
     90 	/**
     91 	 * @tests java.lang.ThreadGroup#ThreadGroup(java.lang.ThreadGroup,
     92 	 *        java.lang.String)
     93 	 */
     94 	public void test_ConstructorLjava_lang_ThreadGroupLjava_lang_String() {
     95 		// Test for method java.lang.ThreadGroup(java.lang.ThreadGroup,
     96 		// java.lang.String)
     97 
     98 		// Unfortunately we have to use other APIs as well as we test the
     99 		// constructor
    100 
    101 		ThreadGroup newGroup = null;
    102 
    103 		try {
    104 			newGroup = new ThreadGroup(null, null);
    105 		} catch (NullPointerException e) {
    106 		}
    107 		assertNull("Can't create a ThreadGroup with a null parent",
    108 				newGroup);
    109 
    110 		newGroup = new ThreadGroup(getInitialThreadGroup(), null);
    111 		assertTrue("Has to be possible to create a subgroup of current group",
    112 				newGroup.getParent() == Thread.currentThread().getThreadGroup());
    113 
    114 		// Lets start all over
    115 		newGroup.destroy();
    116 
    117 		newGroup = new ThreadGroup(getRootThreadGroup(), "a name here");
    118 		assertTrue("Has to be possible to create a subgroup of root group",
    119 				newGroup.getParent() == getRootThreadGroup());
    120 
    121 		// Lets start all over
    122 		newGroup.destroy();
    123 
    124 		try {
    125 			newGroup = new ThreadGroup(newGroup, "a name here");
    126 		} catch (IllegalThreadStateException e) {
    127 			newGroup = null;
    128 		}
    129 		;
    130 		assertNull("Can't create a subgroup of a destroyed group",
    131 				newGroup);
    132 	}
    133 
    134 	/**
    135 	 * @tests java.lang.ThreadGroup#activeCount()
    136 	 */
    137 	public void test_activeCount() {
    138 		// Test for method int java.lang.ThreadGroup.activeCount()
    139 		ThreadGroup tg = new ThreadGroup("activeCount");
    140 		Thread t1 = new Thread(tg, new Runnable() {
    141 			public void run() {
    142 				try {
    143 					Thread.sleep(5000);
    144 				} catch (InterruptedException e) {
    145 				}
    146 			}
    147 		});
    148 		int count = tg.activeCount();
    149 		assertTrue("wrong active count: " + count, count == 0);
    150 		t1.start();
    151 		count = tg.activeCount();
    152 		assertTrue("wrong active count: " + count, count == 1);
    153 		t1.interrupt();
    154 		try {
    155 			t1.join();
    156 		} catch (InterruptedException e) {
    157 		}
    158 		// cleanup
    159 		tg.destroy();
    160 	}
    161 
    162 	/**
    163 	 * @tests java.lang.ThreadGroup#destroy()
    164 	 */
    165 	public void test_destroy() {
    166 		// Test for method void java.lang.ThreadGroup.destroy()
    167 
    168 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    169 		ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
    170 		final int DEPTH = 4;
    171 		final Vector<ThreadGroup> subgroups = buildRandomTreeUnder(testRoot, DEPTH);
    172 
    173 		// destroy them all
    174 		testRoot.destroy();
    175 
    176 		for (int i = 0; i < subgroups.size(); i++) {
    177 			ThreadGroup child = subgroups.elementAt(i);
    178 			assertEquals("Destroyed child can't have children", 0, child
    179 					.activeCount());
    180 			boolean passed = false;
    181 			try {
    182 				child.destroy();
    183 			} catch (IllegalThreadStateException e) {
    184 				passed = true;
    185 			}
    186 			;
    187 			assertTrue("Destroyed child can't be destroyed again", passed);
    188 		}
    189 
    190 		testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
    191 		testRoot.setDaemon(true);
    192 
    193 		ThreadGroup child = new ThreadGroup(testRoot, "daemon child");
    194 
    195 		// If we destroy the last daemon's child, the daemon should get destroyed
    196 		// as well
    197 		child.destroy();
    198 
    199 		boolean passed = false;
    200 		try {
    201 			child.destroy();
    202 		} catch (IllegalThreadStateException e) {
    203 			passed = true;
    204 		}
    205 		;
    206 		assertTrue("Daemon should have been destroyed already", passed);
    207 
    208 		passed = false;
    209 		try {
    210 			testRoot.destroy();
    211 		} catch (IllegalThreadStateException e) {
    212 			passed = true;
    213 		}
    214 		;
    215 		assertTrue("Daemon parent should have been destroyed automatically",
    216 				passed);
    217 
    218 		assertTrue(
    219 				"Destroyed daemon's child should not be in daemon's list anymore",
    220 				!arrayIncludes(groups(testRoot), child));
    221 		assertTrue("Destroyed daemon should not be in parent's list anymore",
    222 				!arrayIncludes(groups(originalCurrent), testRoot));
    223 
    224 		testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
    225 		testRoot.setDaemon(true);
    226 		Thread noOp = new Thread(testRoot, null, "no-op thread") {
    227 			@Override
    228             public void run() {
    229 			}
    230 		};
    231 		noOp.start();
    232 
    233 		// Wait for the no-op thread to run inside daemon ThreadGroup
    234 		try {
    235 			noOp.join();
    236 		} catch (InterruptedException ie) {
    237 			fail("Should not be interrupted");
    238 		}
    239 		;
    240 
    241 		passed = false;
    242 		try {
    243 			child.destroy();
    244 		} catch (IllegalThreadStateException e) {
    245 			passed = true;
    246 		}
    247 		;
    248 		assertTrue(
    249 				"Daemon group should have been destroyed already when last thread died",
    250 				passed);
    251 
    252 		testRoot = new ThreadGroup(originalCurrent, "Test group (daemon)");
    253 		noOp = new Thread(testRoot, null, "no-op thread") {
    254 			@Override
    255             public void run() {
    256 				try {
    257 					Thread.sleep(500);
    258 				} catch (InterruptedException ie) {
    259 					fail("Should not be interrupted");
    260 				}
    261 			}
    262 		};
    263 
    264 		// Has to execute the next lines in an interval < the sleep interval of
    265 		// the no-op thread
    266 		noOp.start();
    267 		passed = false;
    268 		try {
    269 			testRoot.destroy();
    270 		} catch (IllegalThreadStateException its) {
    271 			passed = true;
    272 		}
    273 		assertTrue("Can't destroy a ThreadGroup that has threads", passed);
    274 
    275 		// But after the thread dies, we have to be able to destroy the thread
    276 		// group
    277 		try {
    278 			noOp.join();
    279 		} catch (InterruptedException ie) {
    280 			fail("Should not be interrupted");
    281 		}
    282 		;
    283 		passed = true;
    284 		try {
    285 			testRoot.destroy();
    286 		} catch (IllegalThreadStateException its) {
    287 			passed = false;
    288 		}
    289 		assertTrue(
    290 				"Should be able to destroy a ThreadGroup that has no threads",
    291 				passed);
    292 
    293 	}
    294 
    295 	/**
    296 	 * @tests java.lang.ThreadGroup#destroy()
    297 	 */
    298 	public void test_destroy_subtest0() {
    299 		ThreadGroup group1 = new ThreadGroup("test_destroy_subtest0");
    300 		group1.destroy();
    301 		try {
    302 			new Thread(group1, "test_destroy_subtest0");
    303 			fail("should throw IllegalThreadStateException");
    304 		} catch (IllegalThreadStateException e) {
    305 		}
    306 	}
    307 
    308 	/**
    309 	 * @tests java.lang.ThreadGroup#getMaxPriority()
    310 	 */
    311 	public void test_getMaxPriority() {
    312 		// Test for method int java.lang.ThreadGroup.getMaxPriority()
    313 
    314 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    315 		ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
    316 
    317 		boolean passed = true;
    318 		try {
    319 			testRoot.setMaxPriority(Thread.MIN_PRIORITY);
    320 		} catch (IllegalArgumentException iae) {
    321 			passed = false;
    322 		}
    323 		assertTrue("Should be able to set priority", passed);
    324 
    325 		assertTrue("New value should be the same as we set", testRoot
    326 				.getMaxPriority() == Thread.MIN_PRIORITY);
    327 
    328 		testRoot.destroy();
    329 
    330 	}
    331 
    332 	/**
    333 	 * @tests java.lang.ThreadGroup#getName()
    334 	 */
    335 	public void test_getName() {
    336 		// Test for method java.lang.String java.lang.ThreadGroup.getName()
    337 
    338 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    339 		final String name = "Test group";
    340 		final ThreadGroup testRoot = new ThreadGroup(originalCurrent, name);
    341 
    342 		assertTrue("Setting a name&getting does not work", testRoot.getName()
    343 				.equals(name));
    344 
    345 		testRoot.destroy();
    346 
    347 	}
    348 
    349 	/**
    350 	 * @tests java.lang.ThreadGroup#getParent()
    351 	 */
    352 	public void test_getParent() {
    353 		// Test for method java.lang.ThreadGroup
    354 		// java.lang.ThreadGroup.getParent()
    355 
    356 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    357 		ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
    358 
    359 		assertTrue("Parent is wrong", testRoot.getParent() == originalCurrent);
    360 
    361 		// Create some groups, nested some levels.
    362 		final int TOTAL_DEPTH = 5;
    363 		ThreadGroup current = testRoot;
    364 		Vector<ThreadGroup> groups = new Vector<ThreadGroup>();
    365 		// To maintain the invariant that a thread in the Vector is parent
    366 		// of the next one in the collection (and child of the previous one)
    367 		groups.addElement(testRoot);
    368 
    369 		for (int i = 0; i < TOTAL_DEPTH; i++) {
    370 			current = new ThreadGroup(current, "level " + i);
    371 			groups.addElement(current);
    372 		}
    373 
    374 		// Now we walk the levels down, checking if parent is ok
    375 		for (int i = 1; i < groups.size(); i++) {
    376 			current = groups.elementAt(i);
    377 			ThreadGroup previous = groups.elementAt(i - 1);
    378 			assertTrue("Parent is wrong", current.getParent() == previous);
    379 		}
    380 
    381 		testRoot.destroy();
    382 	}
    383 
    384 	/**
    385 	 * @tests java.lang.ThreadGroup#isDaemon()
    386 	 */
    387 	public void test_isDaemon() {
    388 		// Test for method boolean java.lang.ThreadGroup.isDaemon()
    389 
    390 		daemonTests();
    391 
    392 	}
    393 
    394 	/**
    395 	 * @tests java.lang.ThreadGroup#list()
    396 	 */
    397 	public void test_list() {
    398 		// Test for method void java.lang.ThreadGroup.list()
    399 
    400 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    401 		// wipeSideEffectThreads destroy all side effect of threads created in
    402 		// java.lang.Thread
    403 		boolean result = wipeSideEffectThreads(originalCurrent);
    404 		if (result == false) {
    405             fail("wipe threads in test_list() not successful");
    406         }
    407 		final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
    408 				"Test group");
    409 
    410 		// First save the original System.out
    411 		java.io.PrintStream originalOut = System.out;
    412 
    413 		try {
    414 			java.io.ByteArrayOutputStream contentsStream = new java.io.ByteArrayOutputStream(
    415 					100);
    416 			java.io.PrintStream newOut = new java.io.PrintStream(contentsStream);
    417 
    418 			// We have to "redirect" System.out to test the method 'list'
    419 			System.setOut(newOut);
    420 
    421 			originalCurrent.list();
    422 
    423 			/*
    424 			 * The output has to look like this
    425 			 *
    426 			 * java.lang.ThreadGroup[name=main,maxpri=10] Thread[main,5,main]
    427 			 * java.lang.ThreadGroup[name=Test group,maxpri=10]
    428 			 *
    429 			 */
    430 
    431             String contents = new String(contentsStream.toByteArray());
    432             boolean passed = (contents.indexOf("ThreadGroup[name=main") != -1) &&
    433                              (contents.indexOf("Thread[") != -1) &&
    434                              (contents.indexOf("ThreadGroup[name=Test group") != -1);
    435             assertTrue("'list()' does not print expected contents. "
    436                     + "Result from list: "
    437                     + contents, passed);
    438 			// Do proper cleanup
    439 			testRoot.destroy();
    440 
    441 		} finally {
    442 			// No matter what, we need to restore the original System.out
    443 			System.setOut(originalOut);
    444 		}
    445 
    446 	}
    447 
    448 	/**
    449 	 * @tests java.lang.ThreadGroup#parentOf(java.lang.ThreadGroup)
    450 	 */
    451 	public void test_parentOfLjava_lang_ThreadGroup() {
    452 		// Test for method boolean
    453 		// java.lang.ThreadGroup.parentOf(java.lang.ThreadGroup)
    454 
    455 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    456 		final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
    457 				"Test group");
    458 		final int DEPTH = 4;
    459 		buildRandomTreeUnder(testRoot, DEPTH);
    460 
    461 		final ThreadGroup[] allChildren = allGroups(testRoot);
    462 		for (ThreadGroup element : allChildren) {
    463 			assertTrue("Have to be parentOf all children", testRoot
    464 					.parentOf(element));
    465 		}
    466 
    467 		assertTrue("Have to be parentOf itself", testRoot.parentOf(testRoot));
    468 
    469 		testRoot.destroy();
    470 		assertTrue("Parent can't have test group as subgroup anymore",
    471 				!arrayIncludes(groups(testRoot.getParent()), testRoot));
    472 	}
    473 
    474 	/**
    475 	 * @tests java.lang.ThreadGroup#setDaemon(boolean)
    476 	 */
    477 	public void test_setDaemonZ() {
    478 		// Test for method void java.lang.ThreadGroup.setDaemon(boolean)
    479 
    480 		daemonTests();
    481 
    482 	}
    483 
    484     /*
    485      * @tests java.lang.ThreadGroupt#setDaemon(boolean)
    486      */
    487     public void test_setDaemon_Parent_Child() {
    488         ThreadGroup ptg = new ThreadGroup("Parent");
    489         ThreadGroup ctg = new ThreadGroup(ptg, "Child");
    490 
    491         ctg.setDaemon(true);
    492         assertTrue(ctg.isDaemon());
    493 
    494         ctg.setDaemon(false);
    495         assertFalse(ctg.isDaemon());
    496 
    497         ptg.setDaemon(true);
    498         assertFalse(ctg.isDaemon());
    499 
    500         ptg.setDaemon(false);
    501         assertFalse(ctg.isDaemon());
    502     }
    503 
    504 	/**
    505 	 * @tests java.lang.ThreadGroup#setMaxPriority(int)
    506 	 */
    507 	public void test_setMaxPriorityI() {
    508 		// Test for method void java.lang.ThreadGroup.setMaxPriority(int)
    509 
    510 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    511 		ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group");
    512 
    513 		boolean passed;
    514 
    515 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    516 
    517 		int currentMax = testRoot.getMaxPriority();
    518 		testRoot.setMaxPriority(Thread.MAX_PRIORITY + 1);
    519 		passed = testRoot.getMaxPriority() == currentMax;
    520 		assertTrue(
    521 				"setMaxPriority: Any value higher than the current one is ignored. Before: "
    522 						+ currentMax + " , after: " + testRoot.getMaxPriority(),
    523 				passed);
    524 
    525 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    526 
    527 		currentMax = testRoot.getMaxPriority();
    528 		testRoot.setMaxPriority(Thread.MIN_PRIORITY - 1);
    529 		passed = testRoot.getMaxPriority() == Thread.MIN_PRIORITY;
    530 		assertTrue(
    531 				"setMaxPriority: Any value smaller than MIN_PRIORITY is adjusted to MIN_PRIORITY. Before: "
    532 						+ currentMax + " , after: " + testRoot.getMaxPriority(),
    533 				passed);
    534 
    535 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    536 
    537 		testRoot.destroy();
    538 		testRoot = new ThreadGroup(originalCurrent, "Test group");
    539 
    540 		// Create some groups, nested some levels. Each level will have maxPrio
    541 		// 1 unit smaller than the parent's. However, there can't be a group
    542 		// with priority < Thread.MIN_PRIORITY
    543 		final int TOTAL_DEPTH = testRoot.getMaxPriority() - Thread.MIN_PRIORITY
    544 				- 2;
    545 		ThreadGroup current = testRoot;
    546 		for (int i = 0; i < TOTAL_DEPTH; i++) {
    547 			current = new ThreadGroup(current, "level " + i);
    548 		}
    549 
    550 		// Now we walk the levels down, changing the maxPrio and later verifying
    551 		// that the value is indeed 1 unit smaller than the parent's maxPrio.
    552 		int maxPrio, parentMaxPrio;
    553 		current = testRoot;
    554 
    555 		// To maintain the invariant that when we are to modify a child,
    556 		// its maxPriority is always 1 unit smaller than its parent's.
    557 		// We have to set it for the root manually, and the loop does the rest
    558 		// for all the other sub-levels
    559 		current.setMaxPriority(current.getParent().getMaxPriority() - 1);
    560 
    561 		for (int i = 0; i < TOTAL_DEPTH; i++) {
    562 			maxPrio = current.getMaxPriority();
    563 			parentMaxPrio = current.getParent().getMaxPriority();
    564 
    565 			ThreadGroup[] children = groups(current);
    566 			assertEquals("Can only have 1 subgroup", 1, children.length);
    567 			current = children[0];
    568 			assertTrue(
    569 					"Had to be 1 unit smaller than parent's priority in iteration="
    570 							+ i + " checking->" + current,
    571 					maxPrio == parentMaxPrio - 1);
    572 			current.setMaxPriority(maxPrio - 1);
    573 
    574 			// The next test is sort of redundant, since in next iteration it
    575 			// will be the parent tGroup, so the test will be done.
    576 			assertTrue("Had to be possible to change max priority", current
    577 					.getMaxPriority() == maxPrio - 1);
    578 		}
    579 
    580 		assertTrue(
    581 				"Priority of leaf child group has to be much smaller than original root group",
    582 				current.getMaxPriority() == testRoot.getMaxPriority()
    583 						- TOTAL_DEPTH);
    584 
    585 		testRoot.destroy();
    586 
    587 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    588 
    589 		passed = true;
    590 		testRoot = new ThreadGroup(originalCurrent, "Test group");
    591 		try {
    592 			testRoot.setMaxPriority(Thread.MAX_PRIORITY);
    593 		} catch (IllegalArgumentException iae) {
    594 			passed = false;
    595 		}
    596 		assertTrue(
    597 				"Max Priority = Thread.MAX_PRIORITY should be possible if the test is run with default system ThreadGroup as root",
    598 				passed);
    599 		testRoot.destroy();
    600 	}
    601 
    602 	/**
    603 	 * @tests java.lang.ThreadGroup#uncaughtException(java.lang.Thread,
    604 	 *        java.lang.Throwable)
    605 	 */
    606 	@SuppressWarnings("deprecation")
    607     public void test_uncaughtExceptionLjava_lang_ThreadLjava_lang_Throwable() {
    608 		// Test for method void
    609 		// java.lang.ThreadGroup.uncaughtException(java.lang.Thread,
    610 		// java.lang.Throwable)
    611 
    612 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    613 
    614 		// indices for the array defined below
    615 		final int TEST_DEATH = 0;
    616 		final int TEST_OTHER = 1;
    617 		final int TEST_EXCEPTION_IN_UNCAUGHT = 2;
    618 		final int TEST_OTHER_THEN_DEATH = 3;
    619 		final int TEST_FORCING_THROW_THREAD_DEATH = 4;
    620 		final int TEST_KILLING = 5;
    621 		final int TEST_DEATH_AFTER_UNCAUGHT = 6;
    622 
    623 		final boolean[] passed = new boolean[] { false, false, false, false,
    624 				false, false, false };
    625 
    626 		ThreadGroup testRoot;
    627 		Thread thread;
    628 
    629 		// Our own exception class
    630 		class TestException extends RuntimeException {
    631             private static final long serialVersionUID = 1L;
    632 		}
    633 
    634 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    635 		// - - - - - - -
    636 		testRoot = new ThreadGroup(originalCurrent,
    637 				"Test killing a Thread, forcing it to throw ThreadDeath") {
    638 			@Override
    639             public void uncaughtException(Thread t, Throwable e) {
    640 				if (e instanceof ThreadDeath) {
    641                     passed[TEST_KILLING] = true;
    642                 }
    643 				// always forward, any exception
    644 				super.uncaughtException(t, e);
    645 			}
    646 		};
    647 
    648 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    649 		// - - - - - - -
    650 		testRoot = new ThreadGroup(originalCurrent,
    651 				"Test Forcing a throw of ThreadDeath") {
    652 			@Override
    653             public void uncaughtException(Thread t, Throwable e) {
    654 				if (e instanceof ThreadDeath) {
    655                     passed[TEST_FORCING_THROW_THREAD_DEATH] = true;
    656                 }
    657 				// always forward, any exception
    658 				super.uncaughtException(t, e);
    659 			}
    660 		};
    661 
    662 		// Test if a Thread tells its ThreadGroup about ThreadDeath
    663 		thread = new Thread(testRoot, null, "suicidal thread") {
    664 			@Override
    665             public void run() {
    666 				throw new ThreadDeath();
    667 			}
    668 		};
    669 		thread.start();
    670 		try {
    671 			thread.join();
    672 		} catch (InterruptedException ie) {
    673 			fail("Should not have been interrupted");
    674 		}
    675 		testRoot.destroy();
    676 		assertTrue(
    677 				"Any thread should notify its ThreadGroup about its own death, even if suicide:"
    678 						+ testRoot, passed[TEST_FORCING_THROW_THREAD_DEATH]);
    679 
    680 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    681 		// - - - - - - -
    682 
    683 		testRoot = new ThreadGroup(originalCurrent, "Test ThreadDeath") {
    684 			@Override
    685             public void uncaughtException(Thread t, Throwable e) {
    686 				passed[TEST_DEATH] = false;
    687 				// always forward, any exception
    688 				super.uncaughtException(t, e);
    689 			}
    690 		};
    691 
    692 		// Test if a Thread tells its ThreadGroup about ThreadDeath
    693 		passed[TEST_DEATH] = true;
    694 		thread = new Thread(testRoot, null, "no-op thread");
    695 		thread.start();
    696 		try {
    697 			thread.join();
    698 		} catch (InterruptedException ie) {
    699 			fail("Should not have been interrupted");
    700 		}
    701 		testRoot.destroy();
    702 		assertTrue("A thread should not call uncaughtException when it dies:"
    703 				+ testRoot, passed[TEST_DEATH]);
    704 
    705 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    706 		// - - - - - - -
    707 
    708 		testRoot = new ThreadGroup(originalCurrent, "Test other Exception") {
    709 			@Override
    710             public void uncaughtException(Thread t, Throwable e) {
    711 				if (e instanceof TestException) {
    712                     passed[TEST_OTHER] = true;
    713                 } else {
    714                     // only forward exceptions other than our test
    715 					super.uncaughtException(t, e);
    716                 }
    717 			}
    718 		};
    719 
    720 		// Test if a Thread tells its ThreadGroup about an Exception
    721 		thread = new Thread(testRoot, null, "no-op thread") {
    722 			@Override
    723             public void run() {
    724 				throw new TestException();
    725 			}
    726 		};
    727 		thread.start();
    728 		try {
    729 			thread.join();
    730 		} catch (InterruptedException ie) {
    731 			fail("Should not have been interrupted");
    732 		}
    733 		testRoot.destroy();
    734 		assertTrue(
    735 				"Any thread should notify its ThreadGroup about an uncaught exception:"
    736 						+ testRoot, passed[TEST_OTHER]);
    737 
    738 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    739 		// - - - - - - -
    740 
    741 		// Our own uncaught exception class
    742 		class UncaughtException extends TestException {
    743             private static final long serialVersionUID = 1L;
    744 		}
    745 
    746 		testRoot = new ThreadGroup(originalCurrent,
    747 				"Test Exception in uncaught exception") {
    748 			@Override
    749             public void uncaughtException(Thread t, Throwable e) {
    750 				if (e instanceof TestException) {
    751 					passed[TEST_EXCEPTION_IN_UNCAUGHT] = true;
    752 					// Let's simulate an error inside our uncaughtException
    753 					// method.
    754 					// This should be no-op according to the spec
    755 					throw new UncaughtException();
    756 				}
    757                 // only forward exceptions other than our test
    758                 super.uncaughtException(t, e);
    759 			}
    760 		};
    761 
    762 		// Test if an Exception in uncaughtException is really a no-op
    763 		thread = new Thread(testRoot, null, "no-op thread") {
    764 			@Override
    765             public void run() {
    766 				try {
    767 					throw new TestException();
    768 				} catch (UncaughtException ue) {
    769 					// any exception in my ThreadGroup's uncaughtException must
    770 					// not be propagated.
    771 					// If it gets propagated and we detected that, the test failed
    772 					passed[TEST_EXCEPTION_IN_UNCAUGHT] = false;
    773 				}
    774 			}
    775 		};
    776 		thread.start();
    777 		try {
    778 			thread.join();
    779 		} catch (InterruptedException ie) {
    780 			fail("Should not have been interrupted");
    781 		}
    782 		testRoot.destroy();
    783 		assertTrue(
    784 				"Any uncaughtException in uncaughtException should be no-op:"
    785 						+ testRoot, passed[TEST_EXCEPTION_IN_UNCAUGHT]);
    786 
    787 		// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    788 		// - - - - - - -
    789 
    790 		// This is a mix of 2 of the tests above. It is assumed that ThreadDeath
    791 		// and any random exception do work , tested separately. Now we test
    792 		// if after an uncaughtException is forwarded to the ThreadGroup and
    793 		// the Thread dies, if ThreadDeath is also forwarded. It should be
    794 		// (so that a ThreadGroup can know its Thread died)
    795 		testRoot = new ThreadGroup(originalCurrent,
    796 				"Test Uncaught followed by ThreadDeath") {
    797 			@Override
    798             public void uncaughtException(Thread t, Throwable e) {
    799 				if (e instanceof ThreadDeath) {
    800                     passed[TEST_DEATH_AFTER_UNCAUGHT] = true;
    801                 }
    802 				if (e instanceof TestException) {
    803                     passed[TEST_OTHER_THEN_DEATH] = true;
    804                 } else {
    805                     // only forward exceptions other than our test
    806 					super.uncaughtException(t, e);
    807                 }
    808 			}
    809 		};
    810 
    811 		// Test if a Thread tells its ThreadGroup about an Exception and also
    812 		// ThreadDeath
    813 		thread = new Thread(testRoot, null, "no-op thread") {
    814 			@Override
    815             public void run() {
    816 				throw new TestException();
    817 			}
    818 		};
    819 		thread.start();
    820 		try {
    821 			thread.join();
    822 		} catch (InterruptedException ie) {
    823 			fail("Should not have been interrupted");
    824 		}
    825 		testRoot.destroy();
    826 	}
    827 
    828 	@Override
    829     protected void setUp() {
    830 		initialThreadGroup = Thread.currentThread().getThreadGroup();
    831 		rootThreadGroup = initialThreadGroup;
    832 		while (rootThreadGroup.getParent() != null) {
    833             rootThreadGroup = rootThreadGroup.getParent();
    834         }
    835 	}
    836 
    837 	@Override
    838     protected void tearDown() {
    839 		try {
    840 			// Give the threads a chance to die.
    841 			Thread.sleep(50);
    842 		} catch (InterruptedException e) {
    843 		}
    844 	}
    845 
    846 	private Thread[] threads(ThreadGroup parent) {
    847 		// No API to get the count of immediate children only ?
    848 		int count = parent.activeCount();
    849 		Thread[] all = new Thread[count];
    850 		int actualSize = parent.enumerate(all, false);
    851 		Thread[] result;
    852 		if (actualSize == all.length) {
    853             result = all;
    854         } else {
    855 			result = new Thread[actualSize];
    856 			System.arraycopy(all, 0, result, 0, actualSize);
    857 		}
    858 
    859 		return result;
    860 
    861 	}
    862 
    863 	private ThreadGroup getInitialThreadGroup() {
    864 		return initialThreadGroup;
    865 	}
    866 
    867 	private ThreadGroup[] allGroups(ThreadGroup parent) {
    868 		int count = parent.activeGroupCount();
    869 		ThreadGroup[] all = new ThreadGroup[count];
    870 		parent.enumerate(all, true);
    871 		return all;
    872 	}
    873 
    874 	private void daemonTests() {
    875 		// Test for method void java.lang.ThreadGroup.setDaemon(boolean)
    876 
    877 		final ThreadGroup originalCurrent = getInitialThreadGroup();
    878 		final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
    879 				"Test group");
    880 
    881 		testRoot.setDaemon(true);
    882 		assertTrue("Setting daemon&getting does not work", testRoot.isDaemon());
    883 
    884 		testRoot.setDaemon(false);
    885 		assertTrue("Setting daemon&getting does not work", !testRoot.isDaemon());
    886 
    887 		testRoot.destroy();
    888 
    889 	}
    890 
    891 	private boolean wipeAllThreads(final ThreadGroup aGroup) {
    892 		boolean ok = true;
    893 		Thread[] threads = threads(aGroup);
    894 		for (Thread t : threads) {
    895 			ok = ok && wipeThread(t);
    896 		}
    897 
    898 		// Recursively for subgroups (if any)
    899 		ThreadGroup[] children = groups(aGroup);
    900 		for (ThreadGroup element : children) {
    901 			ok = ok && wipeAllThreads(element);
    902 		}
    903 
    904 		return ok;
    905 
    906 	}
    907 
    908 	private boolean wipeSideEffectThreads(ThreadGroup aGroup) {
    909 		boolean ok = true;
    910 		Thread[] threads = threads(aGroup);
    911 		for (Thread t : threads) {
    912 			if (t.getName().equals("SimpleThread")
    913 					|| t.getName().equals("Bogus Name")
    914 					|| t.getName().equals("Testing")
    915 					|| t.getName().equals("foo")
    916 					|| t.getName().equals("Test Group")
    917 					|| t.getName().equals("Squawk")
    918 					|| t.getName().equals("Thread-1")
    919 					|| t.getName().equals("firstOne")
    920 					|| t.getName().equals("secondOne")
    921 					|| t.getName().equals("Thread-16")
    922 					|| t.getName().equals("Thread-14")) {
    923                 ok = ok && wipeThread(t);
    924             }
    925 		}
    926 
    927 		// Recursively for subgroups (if any)
    928 		ThreadGroup[] children = groups(aGroup);
    929 
    930 		for (ThreadGroup element : children) {
    931 			ok = ok && wipeSideEffectThreads(element);
    932 			if (element.getName().equals("Test Group")
    933 					|| element.getName().equals("foo")
    934 					|| element.getName().equals("jp")) {
    935                 element.destroy();
    936             }
    937 		}
    938 		try {
    939 			// Give the threads a chance to die.
    940 			Thread.sleep(50);
    941 		} catch (InterruptedException e) {
    942 		}
    943 		return ok;
    944 	}
    945 
    946 	private void asyncBuildRandomTreeUnder(final ThreadGroup aGroup,
    947 			final int depth, final Vector<ThreadGroup> allCreated) {
    948 		if (depth <= 0) {
    949             return;
    950         }
    951 
    952 		final int maxImmediateSubgroups = random(3);
    953 		for (int i = 0; i < maxImmediateSubgroups; i++) {
    954 			final int iClone = i;
    955 			final String name = " Depth = " + depth + ",N = " + iClone
    956 					+ ",Vector size at creation: " + allCreated.size();
    957 			// Use concurrency to maximize chance of exposing concurrency bugs
    958 			// in ThreadGroups
    959 			Thread t = new Thread(aGroup, name) {
    960 				@Override
    961                 public void run() {
    962 					ThreadGroup newGroup = new ThreadGroup(aGroup, name);
    963 					allCreated.addElement(newGroup);
    964 					asyncBuildRandomTreeUnder(newGroup, depth - 1, allCreated);
    965 				}
    966 			};
    967 			t.start();
    968 		}
    969 
    970 	}
    971 
    972 	private Vector<ThreadGroup> asyncBuildRandomTreeUnder(final ThreadGroup aGroup,
    973 			final int depth) {
    974 		Vector<ThreadGroup> result = new Vector<ThreadGroup>();
    975 		asyncBuildRandomTreeUnder(aGroup, depth, result);
    976 		return result;
    977 
    978 	}
    979 
    980 	private boolean allSuspended(Vector<MyThread> threads) {
    981 		for (int i = 0; i < threads.size(); i++) {
    982 			MyThread t = threads.elementAt(i);
    983 			if (t.isActivelyRunning()) {
    984                 return false;
    985             }
    986 		}
    987 
    988 		return true;
    989 
    990 	}
    991 
    992 	private ThreadGroup[] groups(ThreadGroup parent) {
    993 		// No API to get the count of immediate children only ?
    994 		int count = parent.activeGroupCount();
    995 		ThreadGroup[] all = new ThreadGroup[count];
    996 		parent.enumerate(all, false);
    997 		// Now we may have nulls in the array, we must find the actual size
    998 		int actualSize = 0;
    999 		for (; actualSize < all.length; actualSize++) {
   1000 			if (all[actualSize] == null) {
   1001                 break;
   1002             }
   1003 		}
   1004 		ThreadGroup[] result;
   1005 		if (actualSize == all.length) {
   1006             result = all;
   1007         } else {
   1008 			result = new ThreadGroup[actualSize];
   1009 			System.arraycopy(all, 0, result, 0, actualSize);
   1010 		}
   1011 
   1012 		return result;
   1013 
   1014 	}
   1015 
   1016 	private Vector<MyThread> populateGroupsWithThreads(final ThreadGroup aGroup,
   1017 			final int threadCount) {
   1018 		Vector<MyThread> result = new Vector<MyThread>();
   1019 		populateGroupsWithThreads(aGroup, threadCount, result);
   1020 		return result;
   1021 
   1022 	}
   1023 
   1024 	private void populateGroupsWithThreads(final ThreadGroup aGroup,
   1025 			final int threadCount, final Vector<MyThread> allCreated) {
   1026 		for (int i = 0; i < threadCount; i++) {
   1027 			final int iClone = i;
   1028 			final String name = "(MyThread)N =" + iClone + "/" + threadCount
   1029 					+ " ,Vector size at creation: " + allCreated.size();
   1030 
   1031 			MyThread t = new MyThread(aGroup, name);
   1032 			allCreated.addElement(t);
   1033 		}
   1034 
   1035 		// Recursively for subgroups (if any)
   1036 		ThreadGroup[] children = groups(aGroup);
   1037 		for (ThreadGroup element : children) {
   1038 			populateGroupsWithThreads(element, threadCount, allCreated);
   1039 		}
   1040 
   1041 	}
   1042 
   1043 	private int random(int max) {
   1044 
   1045 		return 1 + ((new Object()).hashCode() % max);
   1046 
   1047 	}
   1048 
   1049 	@SuppressWarnings("deprecation")
   1050     private boolean wipeThread(Thread t) {
   1051 		t.stop();
   1052 		try {
   1053 			t.join(1000);
   1054 		} catch (InterruptedException ie) {
   1055 			fail("Should not have been interrupted");
   1056 		}
   1057 		// The thread had plenty (subjective) of time to die so there
   1058 		// is a problem.
   1059 		if (t.isAlive()) {
   1060             return false;
   1061         }
   1062 
   1063 		return true;
   1064 	}
   1065 
   1066 	private Vector<ThreadGroup> buildRandomTreeUnder(ThreadGroup aGroup, int depth) {
   1067 		Vector<ThreadGroup> result = asyncBuildRandomTreeUnder(aGroup, depth);
   1068 		while (true) {
   1069 			int sizeBefore = result.size();
   1070 			try {
   1071 				Thread.sleep(1000);
   1072 				int sizeAfter = result.size();
   1073 				// If no activity for a while, we assume async building may be
   1074 				// done.
   1075 				if (sizeBefore == sizeAfter) {
   1076                     // It can only be done if no more threads. Unfortunately we
   1077 					// are relying on this API to work as well.
   1078 					// If it does not, we may loop forever.
   1079 					if (aGroup.activeCount() == 0) {
   1080                         break;
   1081                     }
   1082                 }
   1083 			} catch (InterruptedException e) {
   1084 			}
   1085 		}
   1086 		return result;
   1087 
   1088 	}
   1089 
   1090 	private boolean arrayIncludes(Object[] array, Object toTest) {
   1091 		for (Object element : array) {
   1092 			if (element == toTest) {
   1093                 return true;
   1094             }
   1095 		}
   1096 
   1097 		return false;
   1098 	}
   1099 
   1100 	protected void myassertTrue(String msg, boolean b) {
   1101 		// This method is defined here just to solve a visibility problem
   1102 		// of protected methods with inner types
   1103 		assertTrue(msg, b);
   1104 	}
   1105 
   1106 	private ThreadGroup getRootThreadGroup() {
   1107 		return rootThreadGroup;
   1108 
   1109 	}
   1110 }
   1111