/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package libcore.java.lang; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import junit.framework.TestCase; public class OldThreadGroupTest extends TestCase implements Thread.UncaughtExceptionHandler { class MyThread extends Thread { public volatile int heartBeat = 0; public MyThread(ThreadGroup group, String name) throws SecurityException, IllegalThreadStateException { super(group, name); } @Override public void run() { while (true) { heartBeat++; try { Thread.sleep(50); } catch (InterruptedException e) { break; } } } public boolean isActivelyRunning() { long MAX_WAIT = 100; return isActivelyRunning(MAX_WAIT); } public boolean isActivelyRunning(long maxWait) { int beat = heartBeat; long start = System.currentTimeMillis(); do { Thread.yield(); int beat2 = heartBeat; if (beat != beat2) { return true; } } while (System.currentTimeMillis() - start < maxWait); return false; } } private ThreadGroup initialThreadGroup = null; // A thread that runs in initialThreadGroup throughout each test. private MyThread initialThread; private List myThreads; public void test_activeGroupCount() { ThreadGroup tg = new ThreadGroup("group count"); assertEquals("Incorrect number of groups", 0, tg.activeGroupCount()); Thread t1 = new Thread(tg, new Runnable() { public void run() { } }); assertEquals("Incorrect number of groups", 0, tg.activeGroupCount()); t1.start(); assertEquals("Incorrect number of groups", 0, tg.activeGroupCount()); new ThreadGroup(tg, "test group 1"); assertEquals("Incorrect number of groups", 1, tg.activeGroupCount()); new ThreadGroup(tg, "test group 2"); assertEquals("Incorrect number of groups", 2, tg.activeGroupCount()); } @SuppressWarnings("deprecation") public void test_allowThreadSuspensionZ() { ThreadGroup tg = new ThreadGroup("thread suspension"); assertTrue("Thread suspention can not be changed", tg.allowThreadSuspension(false)); assertTrue("Thread suspention can not be changed", tg.allowThreadSuspension(true)); } public void test_enumerateLThreadArray() { int numThreads = initialThreadGroup.activeCount(); Thread[] listOfThreads = new Thread[numThreads]; int countThread = initialThreadGroup.enumerate(listOfThreads); assertEquals(numThreads, countThread); assertTrue("Initial thread must be in enumeration of threads", Arrays.asList(listOfThreads).contains(initialThread)); } public void test_enumerateLThreadArrayLZtest_enumerateLThreadArrayLZ() throws Exception { // capture the initial condition int initialThreadCount = initialThreadGroup.activeCount(); Thread[] initialThreads = new Thread[initialThreadCount]; assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, false)); assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, true)); assertTrue(Arrays.asList(initialThreads).contains(initialThread)); // start some the threads and see how the count changes ThreadGroup group = new ThreadGroup(initialThreadGroup, "enumerateThreadArray"); int groupSize = 3; List newThreads = populateGroupsWithThreads(group, groupSize); assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, true)); assertTrue(Arrays.asList(initialThreads).contains(initialThread)); for(MyThread thread : newThreads) { thread.start(); } Thread.sleep(500); // starting threads isn't instant! int afterStartCount = initialThreadGroup.activeCount(); Set initialPlusNew = new HashSet(); initialPlusNew.addAll(Arrays.asList(initialThreads)); initialPlusNew.addAll(newThreads); Thread[] afterStartThreads = new Thread[afterStartCount]; assertEquals(afterStartCount, initialThreadGroup.enumerate(afterStartThreads, true)); assertEquals(initialPlusNew, new HashSet(Arrays.asList(afterStartThreads))); assertTrue(Arrays.asList(afterStartThreads).contains(initialThread)); // kill the threads and count 'em again for(MyThread thread : newThreads) { thread.interrupt(); } Thread.sleep(500); // killing threads isn't instant int afterDeathCount = initialThreadGroup.activeCount(); Thread[] afterDeathThreads = new Thread[afterDeathCount]; assertEquals(afterDeathCount, initialThreadGroup.enumerate(afterDeathThreads, false)); assertEquals(Arrays.asList(initialThreads), Arrays.asList(afterDeathThreads)); assertTrue(Arrays.asList(afterDeathThreads).contains(initialThread)); } public void test_enumerateLThreadGroupArray() { int numChildGroupsBefore = initialThreadGroup.activeGroupCount(); ThreadGroup childGroup = new ThreadGroup(initialThreadGroup, "child group"); int numChildGroupsAfter = initialThreadGroup.activeGroupCount(); assertEquals(initialThreadGroup.toString(), numChildGroupsBefore + 1, numChildGroupsAfter); ThreadGroup[] listOfGroups = new ThreadGroup[numChildGroupsAfter]; int countGroupThread = initialThreadGroup.enumerate(listOfGroups); assertEquals(numChildGroupsAfter, countGroupThread); assertTrue(Arrays.asList(listOfGroups).contains(childGroup)); ThreadGroup[] listOfGroups1 = new ThreadGroup[numChildGroupsAfter + 1]; countGroupThread = initialThreadGroup.enumerate(listOfGroups1); assertEquals(numChildGroupsAfter, countGroupThread); assertNull(listOfGroups1[listOfGroups1.length - 1]); ThreadGroup[] listOfGroups2 = new ThreadGroup[numChildGroupsAfter - 1]; countGroupThread = initialThreadGroup.enumerate(listOfGroups2); assertEquals(numChildGroupsAfter - 1, countGroupThread); ThreadGroup thrGroup1 = new ThreadGroup(initialThreadGroup, "Test Group 1"); countGroupThread = thrGroup1.enumerate(listOfGroups); assertEquals(0, countGroupThread); childGroup.destroy(); assertEquals(numChildGroupsBefore + 1, initialThreadGroup.activeGroupCount()); } public void test_enumerateLThreadGroupArrayLZ() { ThreadGroup thrGroup = new ThreadGroup("Test Group 1"); List subThreads = populateGroupsWithThreads(thrGroup, 3); int numGroupThreads = thrGroup.activeGroupCount(); ThreadGroup[] listOfGroups = new ThreadGroup[numGroupThreads]; assertEquals(0, thrGroup.enumerate(listOfGroups, true)); assertEquals(0, thrGroup.enumerate(listOfGroups, false)); for(MyThread thr:subThreads) { thr.start(); } numGroupThreads = thrGroup.activeGroupCount(); listOfGroups = new ThreadGroup[numGroupThreads]; assertEquals(0, thrGroup.enumerate(listOfGroups, true)); assertEquals(0, thrGroup.enumerate(listOfGroups, false)); ThreadGroup subGroup1 = new ThreadGroup(thrGroup, "Test Group 2"); List subThreads1 = populateGroupsWithThreads(subGroup1, 3); numGroupThreads = thrGroup.activeGroupCount(); listOfGroups = new ThreadGroup[numGroupThreads]; assertEquals(1, thrGroup.enumerate(listOfGroups, true)); assertEquals(1, thrGroup.enumerate(listOfGroups, false)); for(MyThread thr:subThreads1) { thr.start(); } numGroupThreads = thrGroup.activeGroupCount(); listOfGroups = new ThreadGroup[numGroupThreads]; assertEquals(1, thrGroup.enumerate(listOfGroups, true)); assertEquals(1, thrGroup.enumerate(listOfGroups, false)); for(MyThread thr:subThreads) { thr.interrupt(); } ThreadGroup subGroup2 = new ThreadGroup(subGroup1, "Test Group 3"); List subThreads2 = populateGroupsWithThreads(subGroup2, 3); numGroupThreads = thrGroup.activeGroupCount(); listOfGroups = new ThreadGroup[numGroupThreads]; assertEquals(2, thrGroup.enumerate(listOfGroups, true)); assertEquals(1, thrGroup.enumerate(listOfGroups, false)); } public void test_getParent() { assertEquals(Thread.currentThread().getThreadGroup(), new ThreadGroup("test").getParent()); assertEquals(initialThreadGroup, new ThreadGroup(initialThreadGroup, "test").getParent()); } /** * java.lang.ThreadGroup#interrupt() */ private static boolean interrupted = false; public void test_interrupt() { Thread.setDefaultUncaughtExceptionHandler(this); ThreadGroup tg = new ThreadGroup("interrupt"); Thread t1 = new Thread(tg, new Runnable() { public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { fail("ok"); } } }); assertFalse("Incorrect state of thread", interrupted); t1.start(); assertFalse("Incorrect state of thread", interrupted); t1.interrupt(); try { t1.join(); } catch (InterruptedException e) { } assertTrue("Incorrect state of thread", interrupted); tg.destroy(); } public void test_isDestroyed() { final ThreadGroup originalCurrent = getInitialThreadGroup(); final ThreadGroup testRoot = new ThreadGroup(originalCurrent, "Test group"); assertFalse("Test group is not destroyed yet", testRoot.isDestroyed()); testRoot.destroy(); assertTrue("Test group already destroyed", testRoot.isDestroyed()); } @SuppressWarnings("deprecation") public void test_resume() { ThreadGroup group = new ThreadGroup("Foo"); Thread thread = launchFiveSecondDummyThread(group); try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } try { group.resume(); fail(); } catch (UnsupportedOperationException expected) { } } private Thread launchFiveSecondDummyThread(ThreadGroup group) { Thread thread = new Thread(group, "Bar") { public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { // Ignore } } }; thread.start(); return thread; } /* * @see java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable) */ public void uncaughtException(Thread t, Throwable e) { interrupted = true; Thread.setDefaultUncaughtExceptionHandler(null); } @Override protected void setUp() { myThreads = new ArrayList<>(); initialThreadGroup = new ThreadGroup(Thread.currentThread().getThreadGroup(), "test group"); initialThread = new MyThread(initialThreadGroup, "initial thread"); myThreads.add(initialThread); initialThread.start(); ThreadGroup rootThreadGroup = initialThreadGroup; while (rootThreadGroup.getParent() != null) { rootThreadGroup = rootThreadGroup.getParent(); } } @Override protected void tearDown() throws Exception { // Make sure we stop any MyThread threads that may have been left running. for (MyThread thread : myThreads) { thread.interrupt(); } // Make sure the threads have stopped. for (MyThread thread : myThreads) { thread.join(2000); if (thread.isAlive()) { fail("Thread " + thread + " did not die as it should have."); } } } private ThreadGroup getInitialThreadGroup() { return initialThreadGroup; } private ThreadGroup[] groups(ThreadGroup parent) { // No API to get the count of immediate children only int count = parent.activeGroupCount(); ThreadGroup[] all = new ThreadGroup[count]; parent.enumerate(all, false); // Now we may have nulls in the array, we must find the actual size int actualSize = 0; for (; actualSize < all.length; actualSize++) { if (all[actualSize] == null) { break; } } return Arrays.copyOfRange(all, 0, actualSize); } private List populateGroupsWithThreads(ThreadGroup group, int threadCount) { List result = new ArrayList(); populateGroupsWithThreads(group, threadCount, result); return result; } private void populateGroupsWithThreads(ThreadGroup group, int threadCount, List out) { for (int i = 0; i < threadCount; i++) { MyThread thread = new MyThread(group, "MyThread " + i + " of " + threadCount); myThreads.add(thread); out.add(thread); } // Recursively for subgroups (if any) ThreadGroup[] children = groups(group); for (ThreadGroup element : children) { populateGroupsWithThreads(element, threadCount, out); } } }