OldThreadGroupTest.java revision ab56f644a3d1a42658d4ec34650f7b882e29e374
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 libcore.java.lang;
19
20import java.util.ArrayList;
21import java.util.Arrays;
22import java.util.HashSet;
23import java.util.List;
24import java.util.Set;
25import junit.framework.TestCase;
26
27public class OldThreadGroupTest extends TestCase implements Thread.UncaughtExceptionHandler {
28
29    class MyThread extends Thread {
30        public volatile int heartBeat = 0;
31
32        public MyThread(ThreadGroup group, String name)
33                throws SecurityException, IllegalThreadStateException {
34            super(group, name);
35        }
36
37        @Override
38        public void run() {
39            while (true) {
40                heartBeat++;
41                try {
42                    Thread.sleep(50);
43                } catch (InterruptedException e) {
44                    break;
45                }
46            }
47        }
48
49        public boolean isActivelyRunning() {
50            long MAX_WAIT = 100;
51            return isActivelyRunning(MAX_WAIT);
52        }
53
54        public boolean isActivelyRunning(long maxWait) {
55            int beat = heartBeat;
56            long start = System.currentTimeMillis();
57            do {
58                Thread.yield();
59                int beat2 = heartBeat;
60                if (beat != beat2) {
61                    return true;
62                }
63            } while (System.currentTimeMillis() - start < maxWait);
64            return false;
65        }
66
67    }
68
69    private ThreadGroup initialThreadGroup = null;
70
71    public void test_activeGroupCount() {
72        ThreadGroup tg = new ThreadGroup("group count");
73        assertEquals("Incorrect number of groups",
74                0, tg.activeGroupCount());
75        Thread t1 = new Thread(tg, new Runnable() {
76            public void run() {
77
78            }
79        });
80        assertEquals("Incorrect number of groups",
81                0, tg.activeGroupCount());
82        t1.start();
83        assertEquals("Incorrect number of groups",
84                0, tg.activeGroupCount());
85        new ThreadGroup(tg, "test group 1");
86        assertEquals("Incorrect number of groups",
87                1, tg.activeGroupCount());
88        new ThreadGroup(tg, "test group 2");
89        assertEquals("Incorrect number of groups",
90                2, tg.activeGroupCount());
91    }
92
93    @SuppressWarnings("deprecation")
94    public void test_allowThreadSuspensionZ() {
95        ThreadGroup tg = new ThreadGroup("thread suspension");
96        assertTrue("Thread suspention can not be changed",
97                tg.allowThreadSuspension(false));
98        assertTrue("Thread suspention can not be changed",
99                tg.allowThreadSuspension(true));
100    }
101
102    /*
103     * Checks whether the current Thread is in the given list.
104     */
105    private boolean inListOfThreads(Thread[] threads) {
106        for (int i = 0; i < threads.length; i++) {
107            if (Thread.currentThread() == threads[i]) {
108                return true;
109            }
110        }
111
112        return false;
113    }
114
115    public void test_enumerateLThreadArray() {
116        int numThreads = initialThreadGroup.activeCount();
117        Thread[] listOfThreads = new Thread[numThreads];
118
119        int countThread = initialThreadGroup.enumerate(listOfThreads);
120        assertEquals(numThreads, countThread);
121        assertTrue("Current thread must be in enumeration of threads",
122                inListOfThreads(listOfThreads));
123    }
124
125    public void test_enumerateLThreadArrayLZtest_enumerateLThreadArrayLZ() throws Exception {
126        // capture the initial condition
127        int initialThreadCount = initialThreadGroup.activeCount();
128        Thread[] initialThreads = new Thread[initialThreadCount];
129        assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, false));
130        assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, true));
131        assertTrue(inListOfThreads(initialThreads));
132
133        // start some the threads and see how the count changes
134        ThreadGroup group = new ThreadGroup(initialThreadGroup, "enumerateThreadArray");
135        int groupSize = 3;
136        List<MyThread> newThreads = populateGroupsWithThreads(group, groupSize);
137        assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, true));
138        assertTrue(inListOfThreads(initialThreads));
139        for(MyThread thread : newThreads) {
140            thread.start();
141        }
142        Thread.sleep(500); // starting threads isn't instant!
143        int afterStartCount = initialThreadGroup.activeCount();
144        Set<Thread> initialPlusNew = new HashSet<Thread>();
145        initialPlusNew.addAll(Arrays.asList(initialThreads));
146        initialPlusNew.addAll(newThreads);
147        Thread[] afterStartThreads = new Thread[afterStartCount];
148        assertEquals(afterStartCount, initialThreadGroup.enumerate(afterStartThreads, true));
149        assertEquals(initialPlusNew, new HashSet<Thread>(Arrays.asList(afterStartThreads)));
150        assertTrue(inListOfThreads(afterStartThreads));
151
152        // kill the threads and count 'em again
153        for(MyThread thread : newThreads) {
154            thread.interrupt();
155        }
156        Thread.sleep(500); // killing threads isn't instant
157        int afterDeathCount = initialThreadGroup.activeCount();
158        Thread[] afterDeathThreads = new Thread[afterDeathCount];
159        assertEquals(afterDeathCount, initialThreadGroup.enumerate(afterDeathThreads, false));
160        assertEquals(Arrays.asList(initialThreads), Arrays.asList(afterDeathThreads));
161        assertTrue(inListOfThreads(afterDeathThreads));
162    }
163
164    public void test_enumerateLThreadGroupArray() {
165        int numGroupThreads = initialThreadGroup.activeGroupCount();
166        ThreadGroup[] listOfGroups = new ThreadGroup[numGroupThreads];
167
168        int countGroupThread = initialThreadGroup.enumerate(listOfGroups);
169        assertEquals(numGroupThreads, countGroupThread);
170
171        ThreadGroup[] listOfGroups1 = new ThreadGroup[numGroupThreads + 1];
172        countGroupThread = initialThreadGroup.enumerate(listOfGroups1);
173        assertEquals(numGroupThreads, countGroupThread);
174        assertNull(listOfGroups1[listOfGroups1.length - 1]);
175
176        ThreadGroup[] listOfGroups2 = new ThreadGroup[numGroupThreads - 1];
177        countGroupThread = initialThreadGroup.enumerate(listOfGroups2);
178        assertEquals(numGroupThreads - 1, countGroupThread);
179
180        ThreadGroup thrGroup1 = new ThreadGroup("Test Group 1");
181        countGroupThread = thrGroup1.enumerate(listOfGroups);
182        assertEquals(0, countGroupThread);
183     }
184
185    public void test_enumerateLThreadGroupArrayLZ() {
186        ThreadGroup thrGroup = new ThreadGroup("Test Group 1");
187        List<MyThread> subThreads = populateGroupsWithThreads(thrGroup, 3);
188        int numGroupThreads = thrGroup.activeGroupCount();
189        ThreadGroup[] listOfGroups = new ThreadGroup[numGroupThreads];
190
191        assertEquals(0, thrGroup.enumerate(listOfGroups, true));
192        assertEquals(0, thrGroup.enumerate(listOfGroups, false));
193
194        for(MyThread thr:subThreads) {
195            thr.start();
196        }
197
198        numGroupThreads = thrGroup.activeGroupCount();
199        listOfGroups = new ThreadGroup[numGroupThreads];
200
201        assertEquals(0, thrGroup.enumerate(listOfGroups, true));
202        assertEquals(0, thrGroup.enumerate(listOfGroups, false));
203
204        ThreadGroup subGroup1 = new ThreadGroup(thrGroup, "Test Group 2");
205        List<MyThread> subThreads1 = populateGroupsWithThreads(subGroup1, 3);
206        numGroupThreads = thrGroup.activeGroupCount();
207        listOfGroups = new ThreadGroup[numGroupThreads];
208
209        assertEquals(1, thrGroup.enumerate(listOfGroups, true));
210        assertEquals(1, thrGroup.enumerate(listOfGroups, false));
211
212        for(MyThread thr:subThreads1) {
213            thr.start();
214        }
215        numGroupThreads = thrGroup.activeGroupCount();
216        listOfGroups = new ThreadGroup[numGroupThreads];
217
218        assertEquals(1, thrGroup.enumerate(listOfGroups, true));
219        assertEquals(1, thrGroup.enumerate(listOfGroups, false));
220
221        for(MyThread thr:subThreads) {
222            thr.interrupt();
223         }
224
225        ThreadGroup subGroup2 = new ThreadGroup(subGroup1, "Test Group 3");
226        List<MyThread> subThreads2 = populateGroupsWithThreads(subGroup2, 3);
227        numGroupThreads = thrGroup.activeGroupCount();
228        listOfGroups = new ThreadGroup[numGroupThreads];
229
230        assertEquals(2, thrGroup.enumerate(listOfGroups, true));
231        assertEquals(1, thrGroup.enumerate(listOfGroups, false));
232    }
233
234    /**
235     * @tests java.lang.ThreadGroup#interrupt()
236     */
237    private static boolean interrupted = false;
238    public void test_interrupt() {
239
240        Thread.setDefaultUncaughtExceptionHandler(this);
241        ThreadGroup tg = new ThreadGroup("interrupt");
242        Thread t1 = new Thread(tg, new Runnable() {
243            public void run() {
244                try {
245                    Thread.sleep(5000);
246                } catch (InterruptedException e) {
247                    fail("ok");
248                }
249            }
250        });
251        assertFalse("Incorrect state of thread", interrupted);
252        t1.start();
253        assertFalse("Incorrect state of thread", interrupted);
254        t1.interrupt();
255        try {
256            t1.join();
257        } catch (InterruptedException e) {
258        }
259        assertTrue("Incorrect state of thread", interrupted);
260        tg.destroy();
261    }
262
263    public void test_isDestroyed() {
264        final ThreadGroup originalCurrent = getInitialThreadGroup();
265        final ThreadGroup testRoot = new ThreadGroup(originalCurrent,
266                "Test group");
267        assertFalse("Test group is not destroyed yet",
268                testRoot.isDestroyed());
269        testRoot.destroy();
270        assertTrue("Test group already destroyed",
271                testRoot.isDestroyed());
272    }
273
274    @SuppressWarnings("deprecation")
275    public void test_resume() {
276        ThreadGroup group = new ThreadGroup("Foo");
277
278        Thread thread = launchFiveSecondDummyThread(group);
279
280        try {
281            Thread.sleep(1000);
282        } catch (InterruptedException e) {
283            // Ignore
284        }
285
286        // No-op in Android. Must neither have an effect nor throw an exception.
287        Thread.State state = thread.getState();
288        group.resume();
289        assertEquals(state, thread.getState());
290    }
291
292    private Thread launchFiveSecondDummyThread(ThreadGroup group) {
293        Thread thread = new Thread(group, "Bar") {
294            public void run() {
295                try {
296                    Thread.sleep(5000);
297                } catch (InterruptedException e) {
298                    // Ignore
299                }
300            }
301        };
302
303        thread.start();
304
305        return thread;
306    }
307
308    /*
309     * @see java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable)
310     */
311    public void uncaughtException(Thread t, Throwable e) {
312        interrupted = true;
313        Thread.setDefaultUncaughtExceptionHandler(null);
314    }
315
316    @Override
317    protected void setUp() {
318        initialThreadGroup = Thread.currentThread().getThreadGroup();
319        ThreadGroup rootThreadGroup = initialThreadGroup;
320        while (rootThreadGroup.getParent() != null) {
321            rootThreadGroup = rootThreadGroup.getParent();
322        }
323    }
324
325    @Override
326    protected void tearDown() {
327        try {
328            // Give the threads a chance to die.
329            Thread.sleep(50);
330        } catch (InterruptedException e) {
331        }
332    }
333
334    private ThreadGroup getInitialThreadGroup() {
335        return initialThreadGroup;
336    }
337
338    private ThreadGroup[] groups(ThreadGroup parent) {
339        // No API to get the count of immediate children only
340        int count = parent.activeGroupCount();
341        ThreadGroup[] all = new ThreadGroup[count];
342        parent.enumerate(all, false);
343        // Now we may have nulls in the array, we must find the actual size
344        int actualSize = 0;
345        for (; actualSize < all.length; actualSize++) {
346            if (all[actualSize] == null) {
347                break;
348            }
349        }
350        return Arrays.copyOfRange(all, 0, actualSize);
351    }
352
353    private List<MyThread> populateGroupsWithThreads(ThreadGroup group, int threadCount) {
354        List<MyThread> result = new ArrayList<MyThread>();
355        populateGroupsWithThreads(group, threadCount, result);
356        return result;
357    }
358
359    private void populateGroupsWithThreads(ThreadGroup group, int threadCount, List<MyThread> out) {
360        for (int i = 0; i < threadCount; i++) {
361            out.add(new MyThread(group, "MyThread " + i + " of " + threadCount));
362        }
363
364        // Recursively for subgroups (if any)
365        ThreadGroup[] children = groups(group);
366        for (ThreadGroup element : children) {
367            populateGroupsWithThreads(element, threadCount, out);
368        }
369    }
370}
371