1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.luni.tests.java.lang;
19
20import java.util.Vector;
21
22public 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